#if ((FEATURE_MODE == 2) || (FEATURE_MODE == 0))
#include "sys_usw_ipuc.h"
#include "sys_tsingma_ipuc_tcam.h"
#include "sys_tsingma_nalpm.h"
#include "sys_usw_ofb.h"
#include "sys_usw_opf.h"
#include "sys_usw_common.h"
#include "sys_usw_ftm.h"
#include "drv_api.h"
#include "sys_usw_register.h"
#include "sys_usw_wb_common.h"

struct sys_nalpm_route_position_s
{
    uint8 valid;
    uint8 snake_idx;
    uint8 offset;
};
typedef struct sys_nalpm_route_position_s sys_nalpm_route_position_t;

struct sys_nalpm_match_tcam_idx_s
{
    sys_nalpm_route_info_t* p_new_route;
    sys_nalpm_route_info_t* p_AD_route;
    sys_nalpm_tcam_item_t * p_tcam_item;
    uint16 tcam_idx;
};
typedef struct sys_nalpm_match_tcam_idx_s sys_nalpm_match_tcam_idx_t;

struct sys_nalpm_son2father_s
{
    trie_t * prefix_trie;
    trie_node_t * p_son_node;
    trie_node_t * p_father_node;
};
typedef struct sys_nalpm_son2father_s sys_nalpm_son2father_t;

struct sys_nalpm_install_route_trie_param_s
{
    uint8 lchip;
    uint8 *p_v4_cnt;
    sys_nalpm_tcam_item_t * p_install_tcam;
    sys_nalpm_route_info_t** p_new_route;
    uint8 new_tcam;
    uint16 clear_array[SYS_NALPM_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4];
    uint16 index_array[SYS_NALPM_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4];
    uint8 cur_idx;
    uint8 clear_idx;
};
typedef struct sys_nalpm_install_route_trie_param_s sys_nalpm_install_route_trie_param_t;


struct sys_nalpm_cookie_s
{
    uint8 lchip;

    sys_nalpm_tcam_item_t * p_install_tcam;
    uint8 new_tcam;
    uint8 merge_cnt;
    sys_nalpm_tcam_item_t * p_chd_tcam;

    uint32 ds_snake_split[SYS_NALPM_MAX_SNAKE][12];
    uint32 ds_snake_split_mask[SYS_NALPM_MAX_SNAKE][12];
    uint32 ds_snake_root[SYS_NALPM_MAX_SNAKE][12];
    uint32 ds_snake_root_mask[SYS_NALPM_MAX_SNAKE][12];


    uint16 clear_array[SYS_NALPM_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4];
    uint8 clear_cnt;

    uint16 index_array[SYS_NALPM_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4];
    uint8 split_cnt;
    uint8 cur_idx;


    uint8 route_in_new_trie;
    sys_nalpm_route_info_t*p_new_route;

}
;
typedef struct sys_nalpm_cookie_s sys_nalpm_cookie_t;


#define NALPM_BUCKET_SUB_BKT(lchip, bkt_idx) NALPM_BUCKET(lchip, bkt_idx).sub_bkt
#define NALPM_BUCKET_USE_CNT(lchip, bkt_idx) NALPM_BUCKET(lchip, bkt_idx).use_cnt
#define NALPM_BUCKET_CNT_USE_LIST(lchip, cnt)  g_sys_nalpm_master[lchip]->bkt_use_list[cnt]

#define NALPM_BUCKET_MGR_EN(lchip, ip_ver) (g_sys_nalpm_master[lchip]->bkt_mgr_en && ip_ver == CTC_IP_VER_4)
#define NALPM_TRIE_MEGER_EN(lchip, ip_ver) (g_sys_nalpm_master[lchip]->trie_merg_en)


#define NALPM_BUKCET_SNAKE_NUM(lchip) (g_sys_nalpm_master[lchip]->snake_per_group*g_sys_nalpm_master[lchip]->snake_group_num)

#define NALPM_BUCKET_MAX_ENTRY(lchip) (NALPM_BUKCET_SNAKE_NUM(lchip)*ROUTE_NUM_PER_SNAKE_V4)


/* iteration macro. */
#define SYS_NALPM_BUCKET_LOOP(lchip, i, sram_type, sram_idx, route_per_snake, snake_entry_cnt) \
    route_per_snake = _sys_nalpm_get_snake_route_num(lchip, sram_type);\
    for (i = 0; i < NALPM_BUKCET_DB_SNAKE_NUM(lchip, sram_type); i++)\
        if( (NALPM_BUCKET(lchip, sram_idx).bitmap[i] != 0) \
            && (snake_entry_cnt = NALPM_SNAKE_IS_COMPACT(lchip, sram_type, i)?ROUTE_NUM_PER_SNAKE_V6_COMPACT:route_per_snake))

#define SYS_NALPM_BUCKET_TRANVAS(lchip, i, sram_type, sram_idx, route_per_snake, snake_entry_cnt) \
    route_per_snake = _sys_nalpm_get_snake_route_num(lchip, sram_type);\
    for (i = 0; i < NALPM_BUKCET_DB_SNAKE_NUM(lchip, sram_type); i++)\
        if((snake_entry_cnt = NALPM_SNAKE_IS_COMPACT(lchip, sram_type, i)?ROUTE_NUM_PER_SNAKE_V6_COMPACT:route_per_snake))



#define COMPACT_DATA_BIT_NUM 72
#define ABS(n) ((((int32)(n)) < 0) ? -(n) : (n))

extern sys_ipuc_master_t* p_usw_ipuc_master[];
sys_nalpm_master_t* g_sys_nalpm_master[CTC_MAX_LOCAL_CHIP_NUM_PP] = {NULL};
extern int32 _sys_usw_ipuc_bind_nexthop(uint8 lchip, sys_ipuc_param_t* p_sys_param, uint8 is_bind);

extern int32
sys_tsingma_ipuc_tcam_get_merge_en(uint8 lchip, uint8 ip_ver, uint8 mask_len);

int32
_sys_tsingma_nalpm_find_best_position(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, uint8 masklen, uint8* snake_idx, uint8* offset);

int32
_sys_tsingma_nalpm_dump_route(uint8 lchip, uint8 i, sys_nalpm_route_info_t* p_ipuc_data);

int32
sys_tsingma_nalpm_merge_prefix(uint8 lchip, uint32 vrf_id, uint32 sram_idx);

STATIC int32
_sys_tsingma_nalpm_bucket_list_update(uint8 lchip, uint16 sram_idx, int32 incr_cnt)
{

    if (NALPM_BUCKET_USE_CNT(lchip, sram_idx))
    {
        ctc_list_pointer_delete(&NALPM_BUCKET_CNT_USE_LIST(lchip, NALPM_BUCKET_USE_CNT(lchip, sram_idx)),
                                (ctc_list_pointer_node_t*)&NALPM_BUCKET(lchip, sram_idx));
    }

    NALPM_BUCKET_USE_CNT(lchip, sram_idx) +=  incr_cnt;

    if (NALPM_BUCKET_USE_CNT(lchip, sram_idx))
    {
        ctc_list_pointer_insert_tail(&NALPM_BUCKET_CNT_USE_LIST(lchip, NALPM_BUCKET_USE_CNT(lchip, sram_idx)),
                                     (ctc_list_pointer_node_t*)&NALPM_BUCKET(lchip, sram_idx));
    }


    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_get_route_num_per_tcam(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, uint8* cnt)
{
    uint8 i = 0, j = 0;

    for (i = 0; i < SYS_NALPM_MAX_SNAKE; i++)
    {
        for (j = 0; j < ROUTE_NUM_PER_SNAKE_V4; j++)
        {
            if (NULL != p_tcam_item->p_ipuc_info_array[i][j])
            {
                (*cnt)++;
            }
        }
    }
    return CTC_E_NONE;
}

extern int32 _sys_tsingma_ipuc_tcam_get_blockid(uint8 lchip,
                                uint8 ip_ver,
                                uint8 masklen,
                                sys_ipuc_route_mode_t route_mode,
                                uint8 hash_conflict,
                                uint8* block_id);


STATIC int32
_sys_tsingma_nalpm_set_sram_type(uint8 lchip, uint8 ip_ver, uint8 router_mask_len, sys_nalpm_tcam_item_t* p_tcam_item)
{
    if (ip_ver == CTC_IP_VER_6)
    {
        if ( router_mask_len <= 64 && g_sys_nalpm_master[lchip]->use_snake64)
        {
            p_tcam_item->sram_type = (g_sys_nalpm_master[lchip]->v6_mode)? SYS_NALPM_SRAM_TYPE_V6_64_EXT: SYS_NALPM_SRAM_TYPE_V6_64;
        }
        else
        {
            p_tcam_item->sram_type = (p_tcam_item->p_prefix_info->tcam_masklen > 64 && g_sys_nalpm_master[lchip]->v6_mode)?
                                     SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT: SYS_NALPM_SRAM_TYPE_V6_128;
        }
    }
    else
    {
        p_tcam_item->sram_type = (DRV_IS_TMM(lchip)||DRV_IS_TMG(lchip))? SYS_NALPM_SRAM_TYPE_V4_EXT: SYS_NALPM_SRAM_TYPE_V4_32;
    }

    return 0;
}



STATIC int32
_sys_tsingma_nalpm_get_bucket_entry_cnt(uint8 lchip, uint8 sram_type)
{
    uint32 count = 0;

    switch(sram_type)
    {
    case SYS_NALPM_SRAM_TYPE_V4_32:
    case SYS_NALPM_SRAM_TYPE_V4_EXT:
        count = ROUTE_NUM_PER_SNAKE_V4*NALPM_BUKCET_SNAKE_NUM(lchip);
        break;
    case SYS_NALPM_SRAM_TYPE_V6_64:
        count = ROUTE_NUM_PER_SNAKE_V6_64*NALPM_BUKCET_SNAKE_NUM(lchip);
        count *= g_sys_nalpm_master[lchip]->ipv6_couple_mode?2:1;
        break;
    case SYS_NALPM_SRAM_TYPE_V6_64_EXT:
    case SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT:
        count = ROUTE_NUM_PER_SNAKE_V6_64*NALPM_BUKCET_SNAKE_NUM(lchip);
        count += g_sys_nalpm_master[lchip]->v6_mode? (g_sys_nalpm_master[lchip]->ipsa_enable ?4:4*2): 0;
        break;
    case SYS_NALPM_SRAM_TYPE_V6_128:
        count = ROUTE_NUM_PER_SNAKE_V6_128*NALPM_BUKCET_SNAKE_NUM(lchip);
        count *= g_sys_nalpm_master[lchip]->ipv6_couple_mode?2:1;
        break;
    default:
        break;
    }

    return count;
}

int32
_sys_tsingma_nalpm_get_bucket_snake_cnt(uint8 lchip, uint8 sram_type)
{
    uint32 count = 0;

    switch(sram_type)
    {
    case SYS_NALPM_SRAM_TYPE_V4_32:
    case SYS_NALPM_SRAM_TYPE_V4_EXT:
        count = NALPM_BUKCET_SNAKE_NUM(lchip);
        break;
    case SYS_NALPM_SRAM_TYPE_V6_64:
        count = NALPM_BUKCET_SNAKE_NUM(lchip);
        count *= g_sys_nalpm_master[lchip]->ipv6_couple_mode?2:1;
        break;
    case SYS_NALPM_SRAM_TYPE_V6_64_EXT:
    case SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT:
        count =  NALPM_BUKCET_SNAKE_NUM(lchip);
        count += g_sys_nalpm_master[lchip]->v6_mode? (g_sys_nalpm_master[lchip]->ipsa_enable ?1:2): 0;
        break;
    case SYS_NALPM_SRAM_TYPE_V6_128:
        count = NALPM_BUKCET_SNAKE_NUM(lchip);
        count *= g_sys_nalpm_master[lchip]->ipv6_couple_mode?2:1;
        break;
    default:
        break;
    }

    return count;
}




int32
_sys_tsingma_nalpm_tcam_idx_alloc(uint8 lchip, ctc_ipuc_param_t*  p_ipuc_param, sys_nalpm_tcam_item_t* p_tcam_item)
{
    uint8 ip_ver = p_tcam_item->p_prefix_info->ip_ver;
    sys_ipuc_tcam_data_t tcam_data = {0};
    tcam_data.key_type = SYS_IPUC_TCAM_FLAG_ALPM;
    tcam_data.masklen = p_tcam_item->p_prefix_info->tcam_masklen;
    tcam_data.ipuc_param = p_ipuc_param;
    tcam_data.info = (void*)(p_tcam_item);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if(p_usw_ipuc_master[lchip]->lpm_tcam_spec[ip_ver] != 0
     && p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] >= p_usw_ipuc_master[lchip]->lpm_tcam_spec[ip_ver])
    {
        return CTC_E_NO_RESOURCE;
    }
    if(DRV_IS_TSINGMA(lchip) && p_ipuc_param->masklen > 64 &&
       p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM] >= p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM]
       && !p_usw_ipuc_master[lchip]->host_lpm_mode)
    {
        return CTC_E_NO_RESOURCE;
    }

    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
    {
        tcam_data.key_index = p_tcam_item->tcam_idx;
    }
    CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->alloc_tcam_key_index(lchip, &tcam_data));
    p_tcam_item->tcam_idx= tcam_data.key_index;
    if (0xff == lchip)
    {
        return CTC_E_INVALID_PARAM;
    }
    if(ip_ver && IS_SHORT_KEY(0, p_tcam_item->tcam_idx))
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] += 2;
    }
    else if(ip_ver)
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] += 4;
    }
    else
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver]++;
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "%s(), tcam_idx=[%u]\n",__FUNCTION__, p_tcam_item->tcam_idx);
    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_tcam_idx_free(uint8 lchip, ctc_ipuc_param_t*  p_ipuc_param, sys_nalpm_tcam_item_t* p_tcam_item)
{
    uint8 ip_ver = p_tcam_item->p_prefix_info->ip_ver;
    sys_ipuc_tcam_data_t tcam_data = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "%s(), tcam_idx=[%u]\n",__FUNCTION__, p_tcam_item->tcam_idx);
    tcam_data.key_type = SYS_IPUC_TCAM_FLAG_ALPM;
    tcam_data.masklen = p_tcam_item->p_prefix_info->tcam_masklen;
    tcam_data.ipuc_param = p_ipuc_param;
    tcam_data.key_index = p_tcam_item->tcam_idx;
    tcam_data.info = (void*)(p_tcam_item);
    CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->free_tcam_key_index(lchip, &tcam_data));

    if(ip_ver && IS_SHORT_KEY(0, p_tcam_item->tcam_idx))
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] -= 2;
    }
    else if(ip_ver)
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] -= 4;
    }
    else
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver]--;
    }

    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_sram_idx_alloc(uint8 lchip, uint8  ip_ver, uint16* p_sram_idx, uint8* p_sub_bkt, uint8 is_root)
{
    int32 ret = CTC_E_NONE;
    uint32 sram_idx = 0;
    uint32 block_size = 0;
    sys_usw_opf_t opf;
    sys_nalpm_bucket_t* p_bucket = NULL;
    CTC_PTR_VALID_CHECK(p_sram_idx);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_index = 0;
    if(DRV_IS_TSINGMA(lchip))
    {
        if (ip_ver && g_sys_nalpm_master[lchip]->ipv6_couple_mode)
        {
            opf.multiple = 8;
            block_size = 8;
        }
        else
        {
            opf.multiple = 4;
            block_size = 4;
        }
    }
    else
    {
        opf.multiple = 1;
        block_size = 1;
    }

    opf.pool_type = g_sys_nalpm_master[lchip]->opf_type_nalpm;
    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
    {
        CTC_ERROR_RETURN(sys_usw_opf_alloc_offset_from_position(lchip, &opf, block_size, *p_sram_idx));
    }
    else
    {
        ret = (sys_usw_opf_alloc_offset(lchip, &opf, block_size, &sram_idx));

        if (CTC_E_NO_RESOURCE == ret && NALPM_BUCKET_MGR_EN(lchip, ip_ver) && !is_root)
        {
            uint8 i = 0;
            uint8 find = 0;

            for (i = 1; i < g_sys_nalpm_master[lchip]->snake_per_group* 2 *ROUTE_NUM_PER_SNAKE_V4 - 1; i++)
            {
                for (p_bucket = (sys_nalpm_bucket_t*)ctc_list_pointer_head(&g_sys_nalpm_master[lchip]->bkt_use_list[i]);
                     p_bucket;
                     p_bucket = (sys_nalpm_bucket_t*)ctc_list_pointer_next((ctc_list_pointer_node_t*)p_bucket))
                {
                    if (p_bucket->is_root)
                    {
                        continue;
                    }
                    if (p_bucket->sub_bkt < 2)
                    {
                        find = 1;
                        break;
                    }
                }
                if (find)
                {
                    break;
                }
            }

            if (p_bucket && p_bucket->sub_bkt < 2)
            {
                sram_idx = p_bucket->sram_idx;
                ret = CTC_E_NONE;
            }
            else
            {
                return CTC_E_NO_RESOURCE;
            }
        }
        else if (ret)
        {
            return ret;
        }
    }

    if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
    {
        *p_sub_bkt =NALPM_BUCKET_SUB_BKT(lchip, sram_idx);

        NALPM_BUCKET_SUB_BKT(lchip, sram_idx)++;
        NALPM_BUCKET(lchip, sram_idx).sram_idx = sram_idx;
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Nalpm alloc sram index: %u\n", sram_idx);
    *p_sram_idx = (uint16)sram_idx;

    return ret;

}

int32
_sys_tsingma_nalpm_sram_idx_free(uint8 lchip, uint16 sram_idx, uint8 ip_ver)
{
    sys_usw_opf_t opf;
    uint32 block_size = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_index = 0;
    opf.pool_type = g_sys_nalpm_master[lchip]->opf_type_nalpm;

    if (DRV_IS_TSINGMA(lchip))
    {
        if (ip_ver && g_sys_nalpm_master[lchip]->ipv6_couple_mode)
        {
            block_size = 8;
        }
        else
        {
            block_size = 4;
        }
    }
    else
    {
        block_size = 1;
    }

    if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
    {  /*exist entry*/

        NALPM_BUCKET_SUB_BKT(lchip, sram_idx)--;

        if (NALPM_BUCKET_SUB_BKT(lchip, sram_idx) != 0)
        {
            return CTC_E_NONE;
        }
    }

    return sys_usw_opf_free_offset( lchip, &opf, block_size, sram_idx);

}

STATIC int32
_sys_tsingma_nalpm_route_cmp(sys_nalpm_route_info_t* p_route_info_0,
                               sys_nalpm_route_info_t* p_route_info_1)
{
    if(!p_route_info_0 || !p_route_info_1)
    {
        return CTC_E_INVALID_PARAM;
    }

    if (p_route_info_0->ip_ver != p_route_info_1->ip_ver)
    {
        return CTC_E_PARAM_CONFLICT;
    }

    if (p_route_info_0->vrf_id != p_route_info_1->vrf_id)
    {
        return CTC_E_PARAM_CONFLICT;
    }

    if (p_route_info_0->route_masklen != p_route_info_1->route_masklen)
    {
        return CTC_E_PARAM_CONFLICT;
    }

    if (0 != sal_memcmp(p_route_info_0->ip, p_route_info_1->ip,
                        (CTC_IP_VER_4 == p_route_info_0->ip_ver)? sizeof(ip_addr_t):sizeof(ipv6_addr_t)))
    {
        return CTC_E_PARAM_CONFLICT;
    }


    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_route_match(uint8 lchip, sys_nalpm_route_info_t* p_pfx_info, sys_nalpm_route_info_t* p_ipuc_info_1)
{
    uint32 masklen = 0;
    uint32 mask_pfx = 0;
    uint32 hw_pfx[4] = {0};

    if(!p_pfx_info || !p_ipuc_info_1)
    {
        return CTC_E_INVALID_PARAM;
    }

    if(p_pfx_info->tcam_masklen < p_ipuc_info_1->route_masklen)
    {
        masklen = p_pfx_info->tcam_masklen;
    }
    else
    {
        masklen = p_ipuc_info_1->route_masklen;
    }

    SYS_NALPM_CONVERT_TO_MSB(p_pfx_info->ip, p_pfx_info->tcam_masklen, hw_pfx, p_ipuc_info_1->ip_ver);

    if (CTC_IP_VER_4 == p_pfx_info->ip_ver)
    {
        mask_pfx = g_sys_nalpm_master[lchip]->len2pfx[masklen];
        if ((hw_pfx[0] & mask_pfx) != (p_ipuc_info_1->ip[0] & mask_pfx))
        {
            return CTC_E_PARAM_CONFLICT;
        }
    }
    else
    {
        mask_pfx = g_sys_nalpm_master[lchip]->len2pfx[masklen%32];
        if (sal_memcmp(hw_pfx, p_ipuc_info_1->ip,  (masklen/32)*sizeof(uint32))
            || ((hw_pfx[masklen/32] & mask_pfx) != (p_ipuc_info_1->ip[masklen/32] & mask_pfx)))
        {
            return CTC_E_PARAM_CONFLICT;
        }

    }

    return CTC_E_NONE;
}


uint32
sys_tsingma_nalpm_get_hw_sram_idx(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, uint8 snake_idx)
{
    uint32 hw_idx = 0xffffffff;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    if(DRV_IS_TSINGMA(lchip))
    {
        hw_idx =  p_tcam_item->sram_idx;

        if (p_tcam_item->p_prefix_info->ip_ver && g_sys_nalpm_master[lchip]->ipv6_couple_mode)
        {
            if ((p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_64 && snake_idx>1)
                 || (p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_128 && snake_idx>1))
            {
                hw_idx = p_tcam_item->sram_idx + 4;
            }
        }
    }
    else
    {
        hw_idx = p_tcam_item->sram_idx +  (snake_idx%g_sys_nalpm_master[lchip]->snake_per_group) * g_sys_nalpm_master[lchip]->bkt_depth;
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO," hw_sram_idx[%u]\n",hw_idx);
    return hw_idx;
}

uint8
_sys_nalpm_get_snake_route_num(uint8 lchip, uint8 sram_type)
{
    uint8 num = 0;

    switch(sram_type)
    {
        case SYS_NALPM_SRAM_TYPE_V4_32:
        case SYS_NALPM_SRAM_TYPE_V4_EXT:
            num = ROUTE_NUM_PER_SNAKE_V4;
            break;
        case SYS_NALPM_SRAM_TYPE_V6_64:
        case SYS_NALPM_SRAM_TYPE_V6_64_EXT:
        case SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT:
            num = ROUTE_NUM_PER_SNAKE_V6_64;
            break;
        case SYS_NALPM_SRAM_TYPE_V6_128:
            num = ROUTE_NUM_PER_SNAKE_V6_128;
            break;
        default:
            break;
    }

    return num;
}


STATIC uint8
_sys_nalpm_get_snake_bitwdith(uint8 lchip, uint8 sram_type, uint8 snake_idx)
{
    uint8 bit_width = 0;

    switch(sram_type)
    {
        case SYS_NALPM_SRAM_TYPE_V4_32:
        case SYS_NALPM_SRAM_TYPE_V4_EXT:
            bit_width = 0x3F;
            break;

        case SYS_NALPM_SRAM_TYPE_V6_64:
            bit_width = 0x7;
            break;

        case SYS_NALPM_SRAM_TYPE_V6_64_EXT:
        case SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT:
            bit_width= NALPM_SNAKE_IS_COMPACT(lchip, sram_type, snake_idx)?0xF:0x7;
            break;

        case SYS_NALPM_SRAM_TYPE_V6_128:
             bit_width = 0x3;
            break;
        default:
            break;
    }

    return bit_width;
}

int32
sys_nalpm_get_table_id(uint8 lchip, uint8 type, uint8 snake_idx, uint32* p_tbl_id, uint32* p_tbl_id1)
{
    uint32 tbl_id = 0;
    uint32 tbl_id1 = 0;

    switch (type)
    {
        case SYS_NALPM_SRAM_TYPE_V4_32:
            if(DRV_IS_TSINGMA(lchip))
            {
                tbl_id = snake_idx ? DsNeoLpmIpv4Bit32Snake1_t : DsNeoLpmIpv4Bit32Snake_t;
                tbl_id1 =  snake_idx ? DsNeoLpmIpv4Bit32Snake3_t : DsNeoLpmIpv4Bit32Snake2_t;
            }
            else
            {
                if(g_sys_nalpm_master[lchip]->ipsa_enable)
                {
                    tbl_id = DsNeoLpmIpv4Bit32Snake_t;
                    tbl_id1 = DsNeoLpmIpv4Bit32Snake1_t;
                }
                else
                {
                    tbl_id = snake_idx >= g_sys_nalpm_master[lchip]->snake_per_group ? DsNeoLpmIpv4Bit32Snake1_t : DsNeoLpmIpv4Bit32Snake_t;
                }
            }
            break;
        case SYS_NALPM_SRAM_TYPE_V6_64:
            if(DRV_IS_TSINGMA(lchip))
            {
                tbl_id = snake_idx%2 ? DsNeoLpmIpv6Bit64Snake1_t : DsNeoLpmIpv6Bit64Snake_t;
                tbl_id1 =  snake_idx%2 ? DsNeoLpmIpv6Bit64Snake3_t : DsNeoLpmIpv6Bit64Snake2_t;
            }
            else
            {
                if(g_sys_nalpm_master[lchip]->ipsa_enable)
                {
                    tbl_id = DsNeoLpmIpv6Bit64Snake_t;
                    tbl_id1 = DsNeoLpmIpv6Bit64Snake1_t;
                }
                else
                {
                    tbl_id = snake_idx >= g_sys_nalpm_master[lchip]->snake_per_group ? DsNeoLpmIpv6Bit64Snake1_t : DsNeoLpmIpv6Bit64Snake_t;
                }
            }
            break;

        case SYS_NALPM_SRAM_TYPE_V6_128:
            if(DRV_IS_TSINGMA(lchip))
            {
                tbl_id = snake_idx%2 ? DsNeoLpmIpv6Bit128Snake1_t : DsNeoLpmIpv6Bit128Snake_t;
                tbl_id1 =  snake_idx%2 ? DsNeoLpmIpv6Bit128Snake3_t : DsNeoLpmIpv6Bit128Snake2_t;
            }
            else
            {
                if(g_sys_nalpm_master[lchip]->ipsa_enable)
                {
                    tbl_id = DsNeoLpmIpv6Bit128Snake_t;
                    tbl_id1 = DsNeoLpmIpv6Bit128Snake1_t;
                }
                else
                {
                    tbl_id = snake_idx >= g_sys_nalpm_master[lchip]->snake_per_group ? DsNeoLpmIpv6Bit128Snake1_t : DsNeoLpmIpv6Bit128Snake_t;
                }
            }
            break;
        case SYS_NALPM_SRAM_TYPE_V4_EXT:
            if(g_sys_nalpm_master[lchip]->ipsa_enable)
            {
                tbl_id = DsNeoLpmIpv4Bit32SnakeExt_t;
                tbl_id1 = DsNeoLpmIpv4Bit32SnakeExt1_t;
            }
            else
            {
                tbl_id = snake_idx >= g_sys_nalpm_master[lchip]->snake_per_group ? DsNeoLpmIpv4Bit32SnakeExt1_t : DsNeoLpmIpv4Bit32SnakeExt_t;
            }
            break;
        case SYS_NALPM_SRAM_TYPE_V6_64_EXT:
        case SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT:

            if(g_sys_nalpm_master[lchip]->ipsa_enable)
            {
                tbl_id = DsNeoLpmIpv6Bit64SnakeExt_t;
                tbl_id1 = DsNeoLpmIpv6Bit64SnakeExt1_t;
            }
            else
            {
                if (snake_idx == 10)
                {
                    tbl_id = DsNeoLpmIpv6Bit64SnakeExt_t;
                }
                else if(snake_idx == 11)
                {
                    tbl_id = DsNeoLpmIpv6Bit64SnakeExt1_t;
                }
                else
                {
                    tbl_id = snake_idx >= g_sys_nalpm_master[lchip]->snake_per_group ? DsNeoLpmIpv6Bit64SnakeExt1_t : DsNeoLpmIpv6Bit64SnakeExt_t;
                }
            }
            break;

        default:
            break;

    }

    *p_tbl_id = tbl_id;
    *p_tbl_id1 = tbl_id1;

    return CTC_E_NONE;
}

STATIC int32
_sys_tsingma_nalpm_build_compact_snake(uint8 lchip,
                                       sys_nalpm_route_info_t* p_route_info,
                                       void* ds_compact,
                                       void* ds_compact_mask,
                                       uint8 offset,
                                       uint8 prefix_len)
{
    int32 ret = CTC_E_NONE;
    ipv6_addr_t ipv6_addr;
    ipv6_addr_t ipv6_addr_mask;
    uint32 ad_index = 0;
    uint32 masklen = 0;
    sal_memset(ipv6_addr, 0, sizeof(ipv6_addr_t));
    sal_memset(ipv6_addr_mask, 0xff, sizeof(ipv6_addr_t));
    if (p_route_info)
    {
        ad_index = p_route_info->ad_idx;
        masklen = p_route_info->route_masklen;

        if (prefix_len < 64)
        {
            ipv6_addr[0] = p_route_info->ip[1];
            ipv6_addr[1] = p_route_info->ip[0];
        }
        else
        {
            ipv6_addr[0] = p_route_info->ip[3];
            ipv6_addr[1] = p_route_info->ip[2];
            masklen = (masklen >= 64) ? masklen - 64: masklen;
        }
    }

    switch(offset)
    {
    case 0:
        SetDsNeoLpmIpv6Bit64SnakeCompact(A, entry_0_ipAddr_f ,  ds_compact, ipv6_addr);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry1_0_maskLen_f, ds_compact, masklen);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry_0_nexthop_f, ds_compact, ad_index);

        SetDsNeoLpmIpv6Bit64SnakeCompact(A, entry_0_ipAddr_f ,  ds_compact_mask, ipv6_addr_mask);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry1_0_maskLen_f, ds_compact_mask, 0xff);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry_0_nexthop_f, ds_compact_mask, 0x3ffff);
        break;

    case 1:
        SetDsNeoLpmIpv6Bit64SnakeCompact(A, entry_1_ipAddr_f ,  ds_compact, ipv6_addr);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry1_1_maskLen_f, ds_compact, masklen);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry_1_nexthop_f, ds_compact, ad_index);

        SetDsNeoLpmIpv6Bit64SnakeCompact(A, entry_1_ipAddr_f ,  ds_compact_mask, ipv6_addr_mask);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry1_1_maskLen_f, ds_compact_mask, 0xff);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry_1_nexthop_f, ds_compact_mask, 0x3ffff);
        break;

    case 2:
        SetDsNeoLpmIpv6Bit64SnakeCompact(A, entry_2_ipAddr_f ,  ds_compact, ipv6_addr);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry1_2_maskLen_f, ds_compact, masklen);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry_2_nexthop_f, ds_compact, ad_index);

        SetDsNeoLpmIpv6Bit64SnakeCompact(A, entry_2_ipAddr_f ,  ds_compact_mask, ipv6_addr_mask);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry1_2_maskLen_f, ds_compact_mask, 0xff);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry_2_nexthop_f, ds_compact_mask, 0x3ffff);
        break;

    case 3:
        SetDsNeoLpmIpv6Bit64SnakeCompact(A, entry_3_ipAddr_f ,  ds_compact, ipv6_addr);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry1_3_maskLen_f, ds_compact, masklen);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry_3_nexthop_f, ds_compact, ad_index);

        SetDsNeoLpmIpv6Bit64SnakeCompact(A, entry_3_ipAddr_f ,  ds_compact_mask, ipv6_addr_mask);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry1_3_maskLen_f, ds_compact_mask, 0xff);
        SetDsNeoLpmIpv6Bit64SnakeCompact(V, entry_3_nexthop_f, ds_compact_mask, 0x3ffff);
        break;

     default:
        break;
    }


    return ret;
}

STATIC int32
_sys_tsingma_nalpm_do_compact(uint8 lchip,
                              sys_nalpm_tcam_item_t* p_tcam_item,
                              sys_nalpm_cookie_t* p_cookie)
{
    uint8 i  = 0;
    uint8 j = 0;
    uint8 index = 0;
    uint8 compack_snake = g_sys_nalpm_master[lchip]->ipsa_enable?5:10;
    uint8 compack_snake1 = 11;
    DsNeoLpmIpv6Bit64SnakeCompactData_m compact_data;
    DsNeoLpmIpv6Bit64SnakeCompactData_m compact_data_mask;

    /*build compact data*/
    for (j = 0; j < ROUTE_NUM_PER_SNAKE_V6_COMPACT; j++)
    {
             i = compack_snake;

            _sys_tsingma_nalpm_build_compact_snake(lchip, p_tcam_item->p_ipuc_info_array[i][j],
                                                   p_cookie->ds_snake_root[i], p_cookie->ds_snake_root_mask[i], j,
                                                   p_tcam_item->p_prefix_info->tcam_masklen);


        if (!g_sys_nalpm_master[lchip]->ipsa_enable)
        {
            i = compack_snake1;

                _sys_tsingma_nalpm_build_compact_snake(lchip, p_tcam_item->p_ipuc_info_array[i][j],
                                                       p_cookie->ds_snake_root[i], p_cookie->ds_snake_root_mask[i], j,
                                                       p_tcam_item->p_prefix_info->tcam_masklen);
        }

    }

    /*build Ds*/
    for (i = 0; i < NALPM_BUKCET_SNAKE_NUM(lchip); i++)
    {
        if (i < g_sys_nalpm_master[lchip]->snake_per_group )
        {
            index = i;
            CTC_BMP_COPY_RANGE((uint32*)&compact_data, 0,  p_cookie->ds_snake_root[compack_snake], index*COMPACT_DATA_BIT_NUM, COMPACT_DATA_BIT_NUM);
            CTC_BMP_COPY_RANGE((uint32*)&compact_data_mask, 0,  p_cookie->ds_snake_root_mask[compack_snake], index*COMPACT_DATA_BIT_NUM, COMPACT_DATA_BIT_NUM);
            SetDsNeoLpmIpv6Bit64SnakeExt(A, compactData_f, p_cookie->ds_snake_root[i], &compact_data);
            SetDsNeoLpmIpv6Bit64SnakeExt(A, compactData_f, p_cookie->ds_snake_root_mask[i], &compact_data_mask);
        }
        else
        {
            index = i%g_sys_nalpm_master[lchip]->snake_per_group;
            CTC_BMP_COPY_RANGE((uint32*)&compact_data, 0,  p_cookie->ds_snake_root[compack_snake1], index*COMPACT_DATA_BIT_NUM, COMPACT_DATA_BIT_NUM);
            CTC_BMP_COPY_RANGE((uint32*)&compact_data_mask, 0,  p_cookie->ds_snake_root_mask[compack_snake1], index*COMPACT_DATA_BIT_NUM, COMPACT_DATA_BIT_NUM);
            SetDsNeoLpmIpv6Bit64SnakeExt(A, compactData_f, p_cookie->ds_snake_root[i], &compact_data);
            SetDsNeoLpmIpv6Bit64SnakeExt(A, compactData_f, p_cookie->ds_snake_root_mask[i], &compact_data_mask);
        }

    }

    return 0;

}

STATIC int32
_sys_tsingma_nalpm_create_cookie(uint8 lchip,
                                sys_nalpm_tcam_item_t* p_root_item,
                                sys_nalpm_tcam_item_t* p_split_item,
                                sys_nalpm_cookie_t** pp_cookie)
{
    uint8 i = 0;
    uint32 cmd = 0;
    uint32 hw_idx = 0;
    uint32 tbl_id = 0;
    uint32 tbl_id1 = 0;
    uint16 snake_num = 0;
    sys_nalpm_cookie_t* p_cookie = NULL;

    p_cookie =  mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_cookie_t));
    if (!p_cookie)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_cookie, 0, sizeof(sys_nalpm_cookie_t));


    snake_num = DRV_IS_TSINGMA(lchip)? NALPM_BUKCET_DB_SNAKE_NUM(lchip, p_root_item->sram_type):
                                       NALPM_BUKCET_SNAKE_NUM(lchip);

    /*Read Hardware to DB*/
    for (i = 0; i < snake_num; i++)
    {
        if (p_root_item)
        {
            sys_nalpm_get_table_id(lchip, p_root_item->sram_type, i, &tbl_id, &tbl_id1);
            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);

            hw_idx = sys_tsingma_nalpm_get_hw_sram_idx(lchip, p_root_item, i);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, cmd, p_cookie->ds_snake_root[i]));
        }

        if (p_split_item && p_split_item->sub_bkt == 1)
        {
            sys_nalpm_get_table_id(lchip, p_split_item->sram_type, i, &tbl_id, &tbl_id1);
            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);

            hw_idx = sys_tsingma_nalpm_get_hw_sram_idx(lchip, p_split_item, i);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, cmd, p_cookie->ds_snake_split[i]));
        }
    }

    *pp_cookie = p_cookie;

    return CTC_E_NONE;

}


STATIC int32
_sys_tsingma_nalpm_write_route_cookie(uint8 lchip,
                                sys_nalpm_tcam_item_t* p_root_item,
                                sys_nalpm_tcam_item_t* p_split_item,
                                sys_nalpm_cookie_t* p_cookie)
{
#if (1 != SDK_WORK_PLATFORM)
    tbl_entry_t tbl_entry;
#endif
    uint8 loop_lchip = 0;
    uint8 i = 0;
    uint8 sram_type = p_root_item ? p_root_item->sram_type : p_split_item->sram_type;
    uint32 cmd = 0;
    uint32 cmd1 = 0;
    uint32 hw_idx = 0;
    uint32 tbl_id = 0;
    uint32 tbl_id1 = 0;
    uint16 snake_num = 0;

    snake_num = DRV_IS_TSINGMA(lchip)? NALPM_BUKCET_DB_SNAKE_NUM(lchip, sram_type):
                                       NALPM_BUKCET_SNAKE_NUM(lchip);

    /*Read Hardware to DB*/
    for (i = 0; i < snake_num; i++)
    {
        if (p_root_item)
        {
            sys_nalpm_get_table_id(lchip, p_root_item->sram_type, i, &tbl_id, &tbl_id1);
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);

            hw_idx = sys_tsingma_nalpm_get_hw_sram_idx(lchip, p_root_item, i);
#if (1 == SDK_WORK_PLATFORM)
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd, p_cookie->ds_snake_root[i]);
            DO_SLAVE_LOOP_END
            
            if (g_sys_nalpm_master[lchip]->ipsa_enable)
            {
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd1, p_cookie->ds_snake_root[i]);
                DO_SLAVE_LOOP_END
            }
#else
            tbl_entry.data_entry = (uint32*)p_cookie->ds_snake_root[i];
            tbl_entry.mask_entry = (uint32*)p_cookie->ds_snake_root_mask[i];

            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd, &tbl_entry);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm_master[lchip]->ipsa_enable)
            {
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd1, &tbl_entry);
                DO_SLAVE_LOOP_END
            }
#endif
        }

        if (p_split_item)
        {
            sys_nalpm_get_table_id(lchip, p_split_item->sram_type, i, &tbl_id, &tbl_id1);
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);

            hw_idx = sys_tsingma_nalpm_get_hw_sram_idx(lchip, p_split_item, i);
#if (1 == SDK_WORK_PLATFORM)
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd, p_cookie->ds_snake_split[i]);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm_master[lchip]->ipsa_enable)
            {
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd1, p_cookie->ds_snake_split[i]);
                DO_SLAVE_LOOP_END
            }
#else
            tbl_entry.data_entry = (uint32*)p_cookie->ds_snake_split[i];
            tbl_entry.mask_entry = (uint32*)p_cookie->ds_snake_split_mask[i];

            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd, &tbl_entry);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm_master[lchip]->ipsa_enable)
            {
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd1, &tbl_entry);
                DO_SLAVE_LOOP_END
            }
#endif
        }

    }

    return 0;

}

int32
_sys_nalpm_write_sram(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_route_info, uint8 snake_idx,
        uint8 entry_idx, uint8 is_update, void* p_data, void* p_data_mask)
{
    sys_nalpm_sram_entry_type_t type = p_tcam_item->sram_type;
    uint32 cmd = 0;
    uint32 DsNeoLpmMemorySnake[12] = {0};
    uint32 DsNeoLpmMemorySnake_mask[12] = {0};
    void *ptr = DsNeoLpmMemorySnake;
    void* ptr_mask = DsNeoLpmMemorySnake_mask;
    uint32 tbl_id = 0, tbl_id1 = 0;
    uint32 hw_idx = 0;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (NULL == p_data && g_sys_nalpm_master[lchip]->v6_mode && NALPM_SNAKE_IS_COMPACT(lchip, p_tcam_item->sram_type, snake_idx))
    {
        sys_nalpm_cookie_t* p_cookie = NULL;

        /*prepare cookie data*/
        _sys_tsingma_nalpm_create_cookie(lchip, p_tcam_item, NULL, &p_cookie);

        _sys_tsingma_nalpm_do_compact(lchip, p_tcam_item, p_cookie);

        /*write cookie data to hw*/
        _sys_tsingma_nalpm_write_route_cookie(lchip, p_tcam_item, NULL, p_cookie);

        mem_free(p_cookie);

        return CTC_E_NONE;
    }


    ptr = (p_data)?p_data:DsNeoLpmMemorySnake;
    ptr_mask = (p_data_mask) ? p_data_mask : DsNeoLpmMemorySnake_mask;
    if (!p_data)
    {
        sys_nalpm_get_table_id(lchip, type, snake_idx, &tbl_id, &tbl_id1);
        hw_idx = sys_tsingma_nalpm_get_hw_sram_idx(lchip, p_tcam_item, snake_idx);
#if (1 == SDK_WORK_PLATFORM)
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, cmd, ptr));
#endif
    }

    if(g_sys_nalpm_master[lchip]->build_snake_cb[type])
    {
        g_sys_nalpm_master[lchip]->build_snake_cb[type](p_tcam_item, p_route_info, entry_idx, is_update, ptr, ptr_mask);
    }

    if (!p_data)
    {
#if (1 == SDK_WORK_PLATFORM)
        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DO_SLAVE_LOOP_START
        CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd, ptr));
        DO_SLAVE_LOOP_END

        if (g_sys_nalpm_master[lchip]->ipsa_enable)
        {
            DO_SLAVE_LOOP_START
            CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd, ptr));
            DO_SLAVE_LOOP_END
        }
#else
        tbl_entry_t tbl_entry;

        tbl_entry.data_entry = (uint32*)ptr;
        tbl_entry.mask_entry = (uint32*)ptr_mask;
        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DO_SLAVE_LOOP_START
        CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd, &tbl_entry));
        DO_SLAVE_LOOP_END

        if (g_sys_nalpm_master[lchip]->ipsa_enable)
        {
            cmd = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, cmd, &tbl_entry));
            DO_SLAVE_LOOP_END
        }
#endif
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nalpm: write %s[%d],entry_idx[%d]\n", DRV_TABLE_NAME(lchip, tbl_id), hw_idx, entry_idx);
    }
    return CTC_E_NONE;

}

STATIC int32
_sys_tmm_nalpm_move_hit(uint8 lchip,
                                sys_nalpm_tcam_item_t* p_root_item,
                                sys_nalpm_tcam_item_t* p_split_item,
                                sys_nalpm_cookie_t* p_cookie)
{
    uint8 i  = 0;
    uint8 j = 0;
    uint8 new_i = 0;
    uint8 new_j = 0;
    uint8 idx = 0;
    uint8 hit = 0;
    uint8 domain_type = 0;
    uint8 domain_type_old = 0;
    uint32 hw_idx = 0;
    uint32 hw_idx_old = 0;

    for (idx = 0; idx < p_cookie->clear_cnt; idx++)
    {
        /* 1.Get old hit */
        i = (p_cookie->clear_array[idx] >> 8);
        j = (p_cookie->clear_array[idx]& 0xFF);

        hw_idx_old = p_root_item->sram_idx +  (i % g_sys_nalpm_master[lchip]->snake_per_group) * g_sys_nalpm_master[lchip]->bkt_depth;
        domain_type_old = i >= g_sys_nalpm_master[lchip]->snake_per_group ? SYS_AGING_DOMAIN_LPM_HASH_GROUP1 :  SYS_AGING_DOMAIN_LPM_HASH_GROUP0;
        MCHIP_LA(lchip)->get_aging_status(lchip, domain_type_old, ((j << 24) | hw_idx_old), &hit);

        /* 2.Set new hit if hit was set */
        if(hit)
        {
            new_i = (p_cookie->index_array[idx] >> 8);
            new_j = (p_cookie->index_array[idx] & 0xFF);

            hw_idx = p_split_item->sram_idx +  (new_i % g_sys_nalpm_master[lchip]->snake_per_group) * g_sys_nalpm_master[lchip]->bkt_depth;
            domain_type = new_i >= g_sys_nalpm_master[lchip]->snake_per_group ? SYS_AGING_DOMAIN_LPM_HASH_GROUP1 :  SYS_AGING_DOMAIN_LPM_HASH_GROUP0;
            MCHIP_LA(lchip)->set_aging_status(lchip, domain_type, ((new_j << 24) | hw_idx), 0, 1);
            MCHIP_LA(lchip)->set_aging_status(lchip, domain_type_old, ((j << 24) | hw_idx_old), 0, 0);
        }
    }

    return CTC_E_NONE;
}

#if defined(TSINGMA_MX)
/* void
_sys_tmm_nalpm_build_snake_ipv4_32(sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_route_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_data_mask)
{
    sys_ds_ipv4_snake_tmm_t* p_v4_snake_data = NULL;
    sys_ds_ipv4_snake_tmm_t* p_v4_snake_mask = NULL;
    uint32  ipv4_addr = 0;

    p_v4_snake_data = (sys_ds_ipv4_snake_tmm_t*)p_ds_data;
    p_v4_snake_mask = (sys_ds_ipv4_snake_tmm_t*)p_ds_data_mask;
    ipv4_addr = p_route_info->ip[0];

    p_v4_snake_data->entry_type = p_tcam_item->sram_type;
    p_v4_snake_mask->entry_type = 0x7;
    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v4_snake_data->entry0_ipaddr_0_28 = ipv4_addr & 0x1fffffff;
                p_v4_snake_data->entry0_ipaddr_29_31= (ipv4_addr >> 29) & 0x7;
                p_v4_snake_mask->entry0_ipaddr_0_28 = 0x1fffffff;
                p_v4_snake_mask->entry0_ipaddr_29_31= 0x7;

                p_v4_snake_data->entry0_masklen_0_5 = p_route_info->route_masklen;
                p_v4_snake_mask->entry0_masklen_0_5 = 0x3f;
            }
        p_v4_snake_data->entry0_nexthop_0_17 = p_route_info->ad_idx;
        p_v4_snake_mask->entry0_nexthop_0_17 = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v4_snake_data->entry1_ipaddr_0_4  = ipv4_addr & 0x1f;
                p_v4_snake_data->entry1_ipaddr_5_27 = (ipv4_addr >> 5) & 0x7fffff;
                p_v4_snake_data->entry1_ipaddr_28_31= (ipv4_addr >> 28) & 0xf;
                p_v4_snake_mask->entry1_ipaddr_0_4  = 0x1f;
                p_v4_snake_mask->entry1_ipaddr_5_27 = 0x7fffff;
                p_v4_snake_mask->entry1_ipaddr_28_31= 0xf;

                p_v4_snake_data->entry1_masklen_0_5 = p_route_info->route_masklen;
                p_v4_snake_mask->entry1_masklen_0_5 = 0x3f;
            }
            p_v4_snake_data->entry1_nexthop_0_17 = p_route_info->ad_idx;
            p_v4_snake_mask->entry1_nexthop_0_17 = 0x3ffff;
        break;
        case 2:
            if(!is_update)
            {
                p_v4_snake_data->entry2_ipaddr_0_3  = ipv4_addr & 0xf;
                p_v4_snake_data->entry2_ipaddr_4_31 = (ipv4_addr >> 4) & 0xfffffff;
                p_v4_snake_mask->entry2_ipaddr_0_3  = 0xf;
                p_v4_snake_mask->entry2_ipaddr_4_31 = 0xfffffff;

                p_v4_snake_data->entry2_masklen_0_5 = p_route_info->route_masklen;
                p_v4_snake_mask->entry2_masklen_0_5 = 0x3f;
            }
            p_v4_snake_data->entry2_nexthop_0_3  = (p_route_info->ad_idx) & 0xf;
            p_v4_snake_data->entry2_nexthop_4_17 = ((p_route_info->ad_idx) >> 4) & 0x3fff;
            p_v4_snake_mask->entry2_nexthop_0_3  = 0xf;
            p_v4_snake_mask->entry2_nexthop_4_17 = 0x3fff;
        break;
        case 3:
            if(!is_update)
            {
                p_v4_snake_data->entry3_ipaddr_0_2  = ipv4_addr & 0x7;
                p_v4_snake_data->entry3_ipaddr_3_31 = (ipv4_addr >> 3) & 0x1fffffff;
                p_v4_snake_mask->entry3_ipaddr_0_2  = 0x7;
                p_v4_snake_mask->entry3_ipaddr_3_31 = 0x1fffffff;

                p_v4_snake_data->entry3_masklen_0_5 = p_route_info->route_masklen;
                p_v4_snake_mask->entry3_masklen_0_5 = 0x3f;
            }
            p_v4_snake_data->entry3_nexthop_0_2  = (p_route_info->ad_idx) & 0x7;
            p_v4_snake_data->entry3_nexthop_3_17 = ((p_route_info->ad_idx) >> 3) & 0x7fff;
            p_v4_snake_mask->entry3_nexthop_0_2  = 0x7;
            p_v4_snake_mask->entry3_nexthop_3_17 = 0x7fff;
        break;
        case 4:
            if(!is_update)
            {
                p_v4_snake_data->entry4_ipaddr_0_10  = ipv4_addr & 0x7ff;
                p_v4_snake_data->entry4_ipaddr_11_31 = (ipv4_addr >> 11) & 0x1fffff;
                p_v4_snake_mask->entry4_ipaddr_0_10  = 0x7ff;
                p_v4_snake_mask->entry4_ipaddr_11_31 = 0x1fffff;

                p_v4_snake_data->entry4_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_mask->entry4_masklen_0_5  = 0x3f;
            }
            p_v4_snake_data->entry4_nexthop_0_1  = (p_route_info->ad_idx) & 0x3;
            p_v4_snake_data->entry4_nexthop_2_17 = ((p_route_info->ad_idx) >> 2) & 0xffff;
            p_v4_snake_mask->entry4_nexthop_0_1  = 0x3;
            p_v4_snake_mask->entry4_nexthop_2_17 = 0xffff;
        break;
        case 5:
            if(!is_update)
            {
                p_v4_snake_data->entry5_ipaddr_0_9   = ipv4_addr & 0x3ff;
                p_v4_snake_data->entry5_ipaddr_10_31 = (ipv4_addr >> 10) & 0x3fffff;
                p_v4_snake_mask->entry5_ipaddr_0_9   = 0x3ff;
                p_v4_snake_mask->entry5_ipaddr_10_31 = 0x3fffff;

                p_v4_snake_data->entry5_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_mask->entry5_masklen_0_5  = 0x3f;
            }
            p_v4_snake_data->entry5_nexthop_0_9   = (p_route_info->ad_idx) & 0x3ff;
            p_v4_snake_data->entry5_nexthop_10_17 = ((p_route_info->ad_idx) >> 10) & 0xff;
            p_v4_snake_mask->entry5_nexthop_0_9   = 0x3ff;
            p_v4_snake_mask->entry5_nexthop_10_17 = 0xff;
        break;
        default:
        break;
    }
} */

void
_sys_tmm_nalpm_build_snake_ext_ipv4_32_ext(sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_route_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_data_mask)
{
    sys_ds_ipv4_ext_snake_tmm_t* p_v4_snake_data = NULL;
    sys_ds_ipv4_ext_snake_tmm_t* p_v4_snake_mask = NULL;
    uint32  ipv4_addr = 0;

    p_v4_snake_data = (sys_ds_ipv4_ext_snake_tmm_t*)p_ds_data;
    p_v4_snake_mask = (sys_ds_ipv4_ext_snake_tmm_t*)p_ds_data_mask;
    ipv4_addr = p_route_info->ip[0];

    p_v4_snake_data->entry_type = p_tcam_item->sram_type;
    p_v4_snake_mask->entry_type = 0x7;
    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v4_snake_data->entry0_ipaddr_0_28  = ipv4_addr & 0x1fffffff;
                p_v4_snake_data->entry0_ipaddr_29_31 = (ipv4_addr >> 29) & 0x7;
                p_v4_snake_mask->entry0_ipaddr_0_28  = 0x1fffffff;
                p_v4_snake_mask->entry0_ipaddr_29_31 = 0x7;

                p_v4_snake_data->entry0_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_data->entry0_bucketsel    = p_tcam_item->sub_bkt;
                p_v4_snake_mask->entry0_masklen_0_5  = 0x3f;
                p_v4_snake_mask->entry0_bucketsel    = 0x1;
            }
            p_v4_snake_data->entry0_nexthop_0_17  = p_route_info->ad_idx;
            p_v4_snake_mask->entry0_nexthop_0_17  = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v4_snake_data->entry1_ipaddr_0_3   = ipv4_addr & 0xf;
                p_v4_snake_data->entry1_ipaddr_4_26  = (ipv4_addr >> 4) & 0x7fffff;
                p_v4_snake_data->entry1_ipaddr_27_31 = (ipv4_addr >> 27) & 0x1f;
                p_v4_snake_mask->entry1_ipaddr_0_3   = 0xf;
                p_v4_snake_mask->entry1_ipaddr_4_26  = 0x7fffff;
                p_v4_snake_mask->entry1_ipaddr_27_31 = 0x1f;

                p_v4_snake_data->entry1_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_data->entry1_bucketsel    = p_tcam_item->sub_bkt;
                p_v4_snake_mask->entry1_masklen_0_5  = 0x3f;
                p_v4_snake_mask->entry1_bucketsel    = 0x1;
            }
            p_v4_snake_data->entry1_nexthop_0_17  = p_route_info->ad_idx;
            p_v4_snake_mask->entry1_nexthop_0_17  = 0x3ffff;
        break;
        case 2:
            if(!is_update)
            {
                p_v4_snake_data->entry2_ipaddr_0_1   = ipv4_addr & 0x3;
                p_v4_snake_data->entry2_ipaddr_2_31  = (ipv4_addr >> 2) & 0x3fffffff;
                p_v4_snake_mask->entry2_ipaddr_0_1   = 0x3;
                p_v4_snake_mask->entry2_ipaddr_2_31  = 0x3fffffff;

                p_v4_snake_data->entry2_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_data->entry2_bucketsel    = p_tcam_item->sub_bkt;
                p_v4_snake_mask->entry2_masklen_0_5  = 0x3f;
                p_v4_snake_mask->entry2_bucketsel    = 0x1;
            }
            p_v4_snake_data->entry2_nexthop_0_1  = p_route_info->ad_idx & 0x3;
            p_v4_snake_data->entry2_nexthop_2_17 = (p_route_info->ad_idx >> 2) & 0xffff;
            p_v4_snake_mask->entry2_nexthop_0_1  = 0x3;
            p_v4_snake_mask->entry2_nexthop_2_17 = 0xffff;
        break;
        case 3:
            if(!is_update)
            {
                p_v4_snake_data->entry3_ipaddr_0_31  = ipv4_addr;
                p_v4_snake_mask->entry3_ipaddr_0_31  = 0xffffffff;

                p_v4_snake_data->entry3_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_data->entry3_bucketsel    = p_tcam_item->sub_bkt;
                p_v4_snake_mask->entry3_masklen_0_5  = 0x3f;
                p_v4_snake_mask->entry3_bucketsel    = 0x1;
            }
            p_v4_snake_data->entry3_nexthop_0_17  = p_route_info->ad_idx;
            p_v4_snake_mask->entry3_nexthop_0_17  = 0x3ffff;
        break;
        case 4:
            if(!is_update)
            {
                p_v4_snake_data->entry4_ipaddr_0_6   = ipv4_addr & 0x7f;
                p_v4_snake_data->entry4_ipaddr_7_29  = (ipv4_addr >> 7) & 0x7fffff;
                p_v4_snake_data->entry4_ipaddr_30_31 = (ipv4_addr >> 30) & 0x3;
                p_v4_snake_mask->entry4_ipaddr_0_6   = 0x7f;
                p_v4_snake_mask->entry4_ipaddr_7_29  = 0x7fffff;
                p_v4_snake_mask->entry4_ipaddr_30_31 = 0x3;

                p_v4_snake_data->entry4_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_data->entry4_bucketsel    = p_tcam_item->sub_bkt;
                p_v4_snake_mask->entry4_masklen_0_5  = 0x3f;
                p_v4_snake_mask->entry4_bucketsel    = 0x1;
            }
            p_v4_snake_data->entry4_nexthop_0_17  = p_route_info->ad_idx;
            p_v4_snake_mask->entry4_nexthop_0_17  = 0x3ffff;
        break;
        case 5:
            if(!is_update)
            {
                p_v4_snake_data->entry5_ipaddr_0_4   = ipv4_addr & 0x1f;
                p_v4_snake_data->entry5_ipaddr_5_31  = (ipv4_addr >> 5) & 0x7ffffff;
                p_v4_snake_mask->entry5_ipaddr_0_4   = 0x1f;
                p_v4_snake_mask->entry5_ipaddr_5_31  = 0x7ffffff;

                p_v4_snake_data->entry5_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_data->entry5_bucketsel    = p_tcam_item->sub_bkt;
                p_v4_snake_mask->entry5_masklen_0_5  = 0x3f;
                p_v4_snake_mask->entry5_bucketsel    = 0x1;
            }
            p_v4_snake_data->entry5_nexthop_0_4   = p_route_info->ad_idx & 0x1f;
            p_v4_snake_data->entry5_nexthop_5_17  = (p_route_info->ad_idx >> 5) & 0x1ffff;
            p_v4_snake_mask->entry5_nexthop_0_4   = 0x1f;
            p_v4_snake_mask->entry5_nexthop_5_17  = 0x1fff;
        break;
        default:
        break;
    }
}

void
_sys_tmm_nalpm_build_snake_ipv6_64(sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_route_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_data_mask)
{
    sys_ds_ipv6_64_snake_tmm_t* p_v6_64_snake_data = NULL;
    sys_ds_ipv6_64_snake_tmm_t* p_v6_64_snake_mask = NULL;
    uint32 ipv6_addr_low = 0;
    uint32 ipv6_addr_high = 0;
    uint8  masklen = p_route_info->route_masklen;

    if(p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_64 ||
       p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_64_EXT )
    {
        ipv6_addr_low = p_route_info->ip[1];
        ipv6_addr_high = p_route_info->ip[0];
    }
    else /* SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT */
    {
        ipv6_addr_low = p_route_info->ip[3];
        ipv6_addr_high = p_route_info->ip[2];
        masklen = (masklen >= 64)? masklen - 64: masklen;
    }
    
    p_v6_64_snake_data = (sys_ds_ipv6_64_snake_tmm_t*)p_ds_data;
    p_v6_64_snake_mask = (sys_ds_ipv6_64_snake_tmm_t*)p_ds_data_mask;

    p_v6_64_snake_data->entry_type = p_tcam_item->sram_type;
    p_v6_64_snake_mask->entry_type = 0x7;
    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v6_64_snake_data->entry0_ipaddr0_0_28   = ipv6_addr_low & 0x1fffffff;
                p_v6_64_snake_data->entry0_ipaddr0_29_31  = (ipv6_addr_low >> 29) & 0x7;
                p_v6_64_snake_mask->entry0_ipaddr0_0_28   = 0x1fffffff;
                p_v6_64_snake_mask->entry0_ipaddr0_29_31  = 0x7;

                p_v6_64_snake_data->entry0_ipaddr1_0_28   = ipv6_addr_high & 0x1fffffff;
                p_v6_64_snake_data->entry0_ipaddr1_29_31  = (ipv6_addr_high >> 29) & 0x7;
                p_v6_64_snake_mask->entry0_ipaddr1_0_28   = 0x1fffffff;
                p_v6_64_snake_mask->entry0_ipaddr1_29_31  = 0x7;

                p_v6_64_snake_data->entry0_masklen_0_1    = masklen & 0x3;
                p_v6_64_snake_data->entry0_masklen_2_7    = (masklen >> 2) & 0x3f;
                p_v6_64_snake_mask->entry0_masklen_0_1    = 0x3;
                p_v6_64_snake_mask->entry0_masklen_2_7    = 0x3f;
            }
            p_v6_64_snake_data->entry0_nexthop_0_17 = p_route_info->ad_idx;
            p_v6_64_snake_mask->entry0_nexthop_0_17 = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v6_64_snake_data->entry1_ipaddr0_0_25   = ipv6_addr_low & 0x3ffffff;
                p_v6_64_snake_data->entry1_ipaddr0_26_31  = (ipv6_addr_low >> 26) & 0x3f;
                p_v6_64_snake_mask->entry1_ipaddr0_0_25   = 0x3ffffff;
                p_v6_64_snake_mask->entry1_ipaddr0_26_31  = 0x3f;

                p_v6_64_snake_data->entry1_ipaddr1_0_25   = ipv6_addr_high & 0x3ffffff;
                p_v6_64_snake_data->entry1_ipaddr1_26_31  = (ipv6_addr_high >> 26) & 0x3f;
                p_v6_64_snake_mask->entry1_ipaddr1_0_25   = 0x3ffffff;
                p_v6_64_snake_mask->entry1_ipaddr1_26_31  = 0x3f;

                p_v6_64_snake_data->entry1_masklen_0_7    = masklen;
                p_v6_64_snake_mask->entry1_masklen_0_7    = 0xff;
            }
            p_v6_64_snake_data->entry1_nexthop_0_16  = p_route_info->ad_idx & 0x1ffff;
            p_v6_64_snake_data->entry1_nexthop_17_17 = (p_route_info->ad_idx >> 17) & 0x1;
            p_v6_64_snake_mask->entry1_nexthop_0_16  = 0x1ffff;
            p_v6_64_snake_mask->entry1_nexthop_17_17 = 0x1;
        break;
        case 2:
            if(!is_update)
            {
                p_v6_64_snake_data->entry2_ipaddr0_0_22   = ipv6_addr_low & 0x7fffff;
                p_v6_64_snake_data->entry2_ipaddr0_23_31  = (ipv6_addr_low >> 23) & 0x1ff;
                p_v6_64_snake_mask->entry2_ipaddr0_0_22   = 0x7fffff;
                p_v6_64_snake_mask->entry2_ipaddr0_23_31  = 0x1ff;

                p_v6_64_snake_data->entry2_ipaddr1_0_22   = ipv6_addr_high & 0x7fffff;
                p_v6_64_snake_data->entry2_ipaddr1_23_31  = (ipv6_addr_high >> 23) & 0x1ff;
                p_v6_64_snake_mask->entry2_ipaddr1_0_22   = 0x7fffff;
                p_v6_64_snake_mask->entry2_ipaddr1_23_31  = 0x1ff;

                p_v6_64_snake_data->entry2_masklen_0_7    = masklen;
                p_v6_64_snake_mask->entry2_masklen_0_7    = 0xff;
            }
            p_v6_64_snake_data->entry2_nexthop_0_13  = p_route_info->ad_idx & 0x3fff;
            p_v6_64_snake_data->entry2_nexthop_14_17 = (p_route_info->ad_idx >> 14) & 0xf;
            p_v6_64_snake_mask->entry2_nexthop_0_13  = 0x3fff;
            p_v6_64_snake_mask->entry2_nexthop_14_17 = 0xf;
        break;
        default:
        break;
    }
}

void
_sys_tmm_nalpm_build_snake_ipv6_128(sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_route_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_data_mask)
{
    sys_ds_ipv6_128_snake_tmm_t* p_v6_128_snake_data = NULL;
    sys_ds_ipv6_128_snake_tmm_t* p_v6_128_snake_mask = NULL;
    uint32 ipv6_addr[4] = {0};

    p_v6_128_snake_data = (sys_ds_ipv6_128_snake_tmm_t*)p_ds_data;
    p_v6_128_snake_mask = (sys_ds_ipv6_128_snake_tmm_t*)p_ds_data_mask;
    ipv6_addr[0] = p_route_info->ip[3];
    ipv6_addr[1] = p_route_info->ip[2];
    ipv6_addr[2] = p_route_info->ip[1];
    ipv6_addr[3] = p_route_info->ip[0];

    p_v6_128_snake_data->entry_type = p_tcam_item->sram_type;
    p_v6_128_snake_mask->entry_type = 0x7;
    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {

                p_v6_128_snake_data->entry0_ipaddr0_0_28  = ipv6_addr[0] & 0x1fffffff;
                p_v6_128_snake_data->entry0_ipaddr0_29_31 = (ipv6_addr[0] >> 29) & 0x7;
                p_v6_128_snake_mask->entry0_ipaddr0_0_28  = 0x1fffffff;
                p_v6_128_snake_mask->entry0_ipaddr0_29_31 = 0x7;

                p_v6_128_snake_data->entry0_ipaddr1_0_28  = ipv6_addr[1] & 0x1fffffff;
                p_v6_128_snake_data->entry0_ipaddr1_29_31 = (ipv6_addr[1] >> 29) & 0x7;
                p_v6_128_snake_mask->entry0_ipaddr1_0_28  = 0x1fffffff;
                p_v6_128_snake_mask->entry0_ipaddr1_29_31 = 0x7;

                p_v6_128_snake_data->entry0_ipaddr2_0_19  = ipv6_addr[2] & 0xfffff;
                p_v6_128_snake_data->entry0_ipaddr2_20_31 = (ipv6_addr[2] >> 20) & 0xfff;
                p_v6_128_snake_mask->entry0_ipaddr2_0_19  = 0xfffff;
                p_v6_128_snake_mask->entry0_ipaddr2_20_31 = 0xfff;

                p_v6_128_snake_data->entry0_ipaddr3_0_19  = ipv6_addr[3] & 0xfffff;
                p_v6_128_snake_data->entry0_ipaddr3_20_31 = (ipv6_addr[3] >> 20) & 0xfff;
                p_v6_128_snake_mask->entry0_ipaddr3_0_19  = 0xfffff;
                p_v6_128_snake_mask->entry0_ipaddr3_20_31 = 0xfff;

                p_v6_128_snake_data->entry0_masklen_0_1   = p_route_info->route_masklen & 0x3;
                p_v6_128_snake_data->entry0_masklen_2_7   = (p_route_info->route_masklen >> 2) & 0x3f;
                p_v6_128_snake_mask->entry0_masklen_0_1   = 0x3;
                p_v6_128_snake_mask->entry0_masklen_2_7   = 0x3f;
            }
            p_v6_128_snake_data->entry0_nexthop_0_17 = p_route_info->ad_idx;
            p_v6_128_snake_mask->entry0_nexthop_0_17 = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v6_128_snake_data->entry1_ipaddr0_0_16  = ipv6_addr[0] & 0x1ffff;
                p_v6_128_snake_data->entry1_ipaddr0_17_31 = (ipv6_addr[0] >> 17) & 0x7fff;
                p_v6_128_snake_mask->entry1_ipaddr0_0_16  = 0x1ffff;
                p_v6_128_snake_mask->entry1_ipaddr0_17_31 = 0x7fff;

                p_v6_128_snake_data->entry1_ipaddr1_0_16  = ipv6_addr[1] & 0x1ffff;
                p_v6_128_snake_data->entry1_ipaddr1_17_31 = (ipv6_addr[1] >> 17) & 0x7fff;
                p_v6_128_snake_mask->entry1_ipaddr1_0_16  = 0x1ffff;
                p_v6_128_snake_mask->entry1_ipaddr1_17_31 = 0x7fff;

                p_v6_128_snake_data->entry1_ipaddr2_0_16  = ipv6_addr[2] & 0x1ffff;
                p_v6_128_snake_data->entry1_ipaddr2_17_31 = (ipv6_addr[2] >> 17) & 0x7fff;
                p_v6_128_snake_mask->entry1_ipaddr2_0_16  = 0x1ffff;
                p_v6_128_snake_mask->entry1_ipaddr2_17_31 = 0x7fff;

                p_v6_128_snake_data->entry1_ipaddr3_0_7   = ipv6_addr[3] & 0xff;
                p_v6_128_snake_data->entry1_ipaddr3_8_31  = (ipv6_addr[3] >> 8) & 0xffffff;
                p_v6_128_snake_mask->entry1_ipaddr3_0_7   = 0xff;
                p_v6_128_snake_mask->entry1_ipaddr3_8_31  = 0xffffff;

                p_v6_128_snake_data-> entry1_masklen_0_7  = p_route_info->route_masklen;
                p_v6_128_snake_mask-> entry1_masklen_0_7  = 0xff;
            }
            p_v6_128_snake_data->entry1_nexthop_0_7  = p_route_info->ad_idx & 0xff;
            p_v6_128_snake_data->entry1_nexthop_8_17 = (p_route_info->ad_idx >> 8) & 0x3ff;
            p_v6_128_snake_mask->entry1_nexthop_0_7  = 0xff;
            p_v6_128_snake_mask->entry1_nexthop_8_17 = 0x3ff;
        break;
        default:
        break;
    }
}
#endif
#if defined(TSINGMA)
void
_sys_tsingama_nalpm_build_snake_ipv4_32(sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_route_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_data_mask)
{
    sys_ds_ipv4_snake_tm_t* p_v4_snake_data = NULL;
    sys_ds_ipv4_snake_tm_t* p_v4_snake_mask = NULL;
    uint32  ipv4_addr = 0;

    ipv4_addr = p_route_info->ip[0];
    p_v4_snake_data = (sys_ds_ipv4_snake_tm_t*)p_ds_data;
    p_v4_snake_mask = (sys_ds_ipv4_snake_tm_t*)p_ds_data_mask;

    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v4_snake_data->entry0_ipaddr_0_31  = ipv4_addr;
                p_v4_snake_mask->entry0_ipaddr_0_31  = 0xffffffff;

                p_v4_snake_data->entry0_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_mask->entry0_masklen_0_5  = 0x3f;
            }
            p_v4_snake_data->entry0_nexthop_0_17  = p_route_info->ad_idx;
            p_v4_snake_mask->entry0_nexthop_0_17  = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v4_snake_data->entry1_ipaddr_0_7   = ipv4_addr & 0xff;
                p_v4_snake_data->entry1_ipaddr_8_28  = (ipv4_addr >> 8) & 0x1fffff;
                p_v4_snake_data->entry1_ipaddr_29_31 = (ipv4_addr >> 29) & 0x7;
                p_v4_snake_mask->entry1_ipaddr_0_7   = 0xff;
                p_v4_snake_mask->entry1_ipaddr_8_28  = 0x1fffff;
                p_v4_snake_mask->entry1_ipaddr_29_31 = 0x7;

                p_v4_snake_data->entry1_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_mask->entry1_masklen_0_5  = 0x3f;
            }
            p_v4_snake_data->entry1_nexthop_0_17  = p_route_info->ad_idx;
            p_v4_snake_mask->entry1_nexthop_0_17  = 0x3ffff;
        break;
        case 2:
            if(!is_update)
            {
                p_v4_snake_data->entry2_ipaddr_0_4   = ipv4_addr & 0x1f;
                p_v4_snake_data->entry2_ipaddr_5_31  = (ipv4_addr >> 5) & 0x7ffffff;
                p_v4_snake_mask->entry2_ipaddr_0_4   = 0x1f;
                p_v4_snake_mask->entry2_ipaddr_5_31  = 0x7ffffff;

                p_v4_snake_data->entry2_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_mask->entry2_masklen_0_5  = 0x3f;
            }
            p_v4_snake_data->entry2_nexthop_0_4   = p_route_info->ad_idx & 0x1f;
            p_v4_snake_data->entry2_nexthop_5_17  = (p_route_info->ad_idx >> 5) & 0x1fff;
            p_v4_snake_mask->entry2_nexthop_0_4   = 0x1f;
            p_v4_snake_mask->entry2_nexthop_5_17  = 0x1fff;
        break;
        case 3:
            if(!is_update)
            {
                p_v4_snake_data->entry3_ipaddr_0_1   = ipv4_addr & 0x3;
                p_v4_snake_data->entry3_ipaddr_2_31  = (ipv4_addr >> 2) & 0x3fffffff;
                p_v4_snake_mask->entry3_ipaddr_0_1   = 0x3;
                p_v4_snake_mask->entry3_ipaddr_2_31  = 0x3fffffff;

                p_v4_snake_data->entry3_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_mask->entry3_masklen_0_5  = 0x3f;
            }
            p_v4_snake_data->entry3_nexthop_0_1   = p_route_info->ad_idx & 0x3;
            p_v4_snake_data->entry3_nexthop_2_17  = (p_route_info->ad_idx >> 2) & 0xffff;
            p_v4_snake_mask->entry3_nexthop_0_1   = 0x3;
            p_v4_snake_mask->entry3_nexthop_2_17  = 0xffff;
        break;
        case 4:
            if(!is_update)
            {
                p_v4_snake_data->entry4_ipaddr_0_9   = ipv4_addr & 0x3ff;
                p_v4_snake_data->entry4_ipaddr_10_30 = (ipv4_addr >> 10) & 0x1fffff;
                p_v4_snake_data->entry4_ipaddr_31_31 = (ipv4_addr >> 31) & 0x1;
                p_v4_snake_mask->entry4_ipaddr_0_9   = 0x3ff;
                p_v4_snake_mask->entry4_ipaddr_10_30 = 0x1fffff;
                p_v4_snake_mask->entry4_ipaddr_31_31 = 0x1;

                p_v4_snake_data->entry4_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_mask->entry4_masklen_0_5  = 0x3f;
            }
            p_v4_snake_data->entry4_nexthop_0_17  = p_route_info->ad_idx;
            p_v4_snake_mask->entry4_nexthop_0_17  = 0x3ffff;
        break;
        case 5:
            if(!is_update)
            {
                p_v4_snake_data->entry5_ipaddr_0_6   = ipv4_addr & 0x7f;
                p_v4_snake_data->entry5_ipaddr_7_31  = (ipv4_addr >> 7) & 0x1ffffff;
                p_v4_snake_mask->entry5_ipaddr_0_6   = 0x7f;
                p_v4_snake_mask->entry5_ipaddr_7_31  = 0x1ffffff;

                p_v4_snake_data->entry5_masklen_0_5  = p_route_info->route_masklen;
                p_v4_snake_mask->entry5_masklen_0_5  = 0x3f;
            }
            p_v4_snake_data->entry5_nexthop_0_6   = p_route_info->ad_idx & 0x7f;
            p_v4_snake_data->entry5_nexthop_7_17  = (p_route_info->ad_idx >> 7) & 0x7ff;
            p_v4_snake_mask->entry5_nexthop_0_6   = 0x7f;
            p_v4_snake_mask->entry5_nexthop_7_17  = 0x7ff;
        break;
        default:
        break;
    }
}

void
_sys_tsingama_nalpm_build_snake_ipv6_64(sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_route_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_data_mask)
{
    sys_ds_ipv6_64_snake_tm_t* p_v6_64_snake_data = NULL;
    sys_ds_ipv6_64_snake_tm_t* p_v6_64_snake_mask = NULL;
    uint32 ipv6_addr_low = 0;
    uint32 ipv6_addr_high = 0;

    p_v6_64_snake_data = (sys_ds_ipv6_64_snake_tm_t*)p_ds_data;
    p_v6_64_snake_mask = (sys_ds_ipv6_64_snake_tm_t*)p_ds_data_mask;
    ipv6_addr_low = p_route_info->ip[1];
    ipv6_addr_high = p_route_info->ip[0];

    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v6_64_snake_data->entry0_ipaddr0_0_31 = ipv6_addr_low;
                p_v6_64_snake_mask->entry0_ipaddr0_0_31 = 0xffffffff;

                p_v6_64_snake_data->entry0_ipaddr1_0_31 = ipv6_addr_high;
                p_v6_64_snake_mask->entry0_ipaddr1_0_31 = 0xffffffff;

                p_v6_64_snake_data->entry0_masklen_0_2  = p_route_info->route_masklen & 0x7;
                p_v6_64_snake_data->entry0_masklen_3_7  = (p_route_info->route_masklen >> 3) & 0x1f;
                p_v6_64_snake_mask->entry0_masklen_0_2  = 0x7;
                p_v6_64_snake_mask->entry0_masklen_3_7  = 0x1f;
            }
            p_v6_64_snake_data->entry0_nexthop_0_17  = p_route_info->ad_idx;
            p_v6_64_snake_mask->entry0_nexthop_0_17  = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v6_64_snake_data->entry1_ipaddr0_0_26  = ipv6_addr_low & 0x7ffffff;
                p_v6_64_snake_data->entry1_ipaddr0_27_31 = (ipv6_addr_low >> 27) & 0x1f;
                p_v6_64_snake_mask->entry1_ipaddr0_0_26  = 0x7ffffff;
                p_v6_64_snake_mask->entry1_ipaddr0_27_31 = 0x1f;
            
                p_v6_64_snake_data->entry1_ipaddr1_0_26  = ipv6_addr_high & 0x7ffffff;
                p_v6_64_snake_data->entry1_ipaddr1_27_31 = (ipv6_addr_high >> 27) & 0x1f;
                p_v6_64_snake_mask->entry1_ipaddr1_0_26  = 0x7ffffff;
                p_v6_64_snake_mask->entry1_ipaddr1_27_31 = 0x1f;

                p_v6_64_snake_data->entry1_masklen_0_7   = p_route_info->route_masklen;
                p_v6_64_snake_mask->entry1_masklen_0_7   = 0xff;
            }
            p_v6_64_snake_data->entry1_nexthop_0_15  = p_route_info->ad_idx & 0xffff;
            p_v6_64_snake_data->entry1_nexthop_16_17 = (p_route_info->ad_idx >> 16) & 0x3;
            p_v6_64_snake_mask->entry1_nexthop_0_15  = 0xffff;
            p_v6_64_snake_mask->entry1_nexthop_16_17 = 0x3;
        break;
        case 2:
            if(!is_update)
            {
                p_v6_64_snake_data->entry2_ipaddr0_0_21  = ipv6_addr_low & 0x3fffff;
                p_v6_64_snake_data->entry2_ipaddr0_22_31 = (ipv6_addr_low >> 22) & 0x3ff;
                p_v6_64_snake_mask->entry2_ipaddr0_0_21  = 0x3fffff;
                p_v6_64_snake_mask->entry2_ipaddr0_22_31 = 0x3ff;

                p_v6_64_snake_data->entry2_ipaddr1_0_21  = ipv6_addr_high & 0x3fffff;
                p_v6_64_snake_data->entry2_ipaddr1_22_31 = (ipv6_addr_high >> 22) & 0x3ff;
                p_v6_64_snake_mask->entry2_ipaddr1_0_21  = 0x3fffff;
                p_v6_64_snake_mask->entry2_ipaddr1_22_31 = 0x3ff;

                p_v6_64_snake_data->entry2_masklen_0_7   = p_route_info->route_masklen;
                p_v6_64_snake_mask->entry2_masklen_0_7   = 0xff;
            }
            p_v6_64_snake_data->entry2_nexthop_0_10  = p_route_info->ad_idx & 0x7ff;
            p_v6_64_snake_data->entry2_nexthop_11_17 = (p_route_info->ad_idx >> 11) & 0x7f;
            p_v6_64_snake_mask->entry2_nexthop_0_10  = 0x7ff;
            p_v6_64_snake_mask->entry2_nexthop_11_17 = 0x7f;
        break;
        default:
        break;
    }
}

void
_sys_tsingama_nalpm_build_snake_ipv6_128(sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_route_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_data_mask)
{
    sys_ds_ipv6_128_snake_tm_t* p_v6_128_snake_data = NULL;
    sys_ds_ipv6_128_snake_tm_t* p_v6_128_snake_mask = NULL;
    uint32 ipv6_addr[4] = {0};

    p_v6_128_snake_data = (sys_ds_ipv6_128_snake_tm_t*)p_ds_data;
    p_v6_128_snake_mask = (sys_ds_ipv6_128_snake_tm_t*)p_ds_data_mask;
    ipv6_addr[0] = p_route_info->ip[3];
    ipv6_addr[1] = p_route_info->ip[2];
    ipv6_addr[2] = p_route_info->ip[1];
    ipv6_addr[3] = p_route_info->ip[0];

    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v6_128_snake_data->entry0_ipaddr0_0_31  = ipv6_addr[0];
                p_v6_128_snake_mask->entry0_ipaddr0_0_31  = 0xffffffff;

                p_v6_128_snake_data->entry0_ipaddr1_0_31  = ipv6_addr[1];
                p_v6_128_snake_mask->entry0_ipaddr1_0_31  = 0xffffffff;

                p_v6_128_snake_data->entry0_ipaddr2_0_20  = ipv6_addr[2] & 0x1fffff;
                p_v6_128_snake_data->entry0_ipaddr2_21_31 = (ipv6_addr[2] >> 21) & 0x7ff;
                p_v6_128_snake_mask->entry0_ipaddr2_0_20  = 0x1fffff;
                p_v6_128_snake_mask->entry0_ipaddr2_21_31 = 0x7ff;

                p_v6_128_snake_data->entry0_ipaddr3_0_20  = ipv6_addr[3] & 0x1fffff;
                p_v6_128_snake_data->entry0_ipaddr3_21_31 = (ipv6_addr[3] >> 21) & 0x7ff;
                p_v6_128_snake_mask->entry0_ipaddr3_0_20  = 0x1fffff;
                p_v6_128_snake_mask->entry0_ipaddr3_21_31 = 0x7ff;

                p_v6_128_snake_data->entry0_masklen_0_2   = p_route_info->route_masklen & 0x7;
                p_v6_128_snake_data->entry0_masklen_3_7   = (p_route_info->route_masklen >> 3) & 0x1f;
                p_v6_128_snake_mask->entry0_masklen_0_2   = 0x7;
                p_v6_128_snake_mask->entry0_masklen_3_7   = 0x1f;
            }
            p_v6_128_snake_data->entry0_nexthop_0_17  = p_route_info->ad_idx;
            p_v6_128_snake_mask->entry0_nexthop_0_17  = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v6_128_snake_data->entry1_ipaddr0_0_15  = ipv6_addr[0] & 0xffff;
                p_v6_128_snake_data->entry1_ipaddr0_16_31 = (ipv6_addr[0] >> 16) & 0xffff;
                p_v6_128_snake_mask->entry1_ipaddr0_0_15  = 0xffff;
                p_v6_128_snake_mask->entry1_ipaddr0_16_31 = 0xffff;

                p_v6_128_snake_data->entry1_ipaddr1_0_15  = ipv6_addr[1] & 0xffff;
                p_v6_128_snake_data->entry1_ipaddr1_16_31 = (ipv6_addr[1] >> 16) & 0xffff;
                p_v6_128_snake_mask->entry1_ipaddr1_0_15  = 0xffff;
                p_v6_128_snake_mask->entry1_ipaddr1_16_31 = 0xffff;

                p_v6_128_snake_data->entry1_ipaddr2_0_15  = ipv6_addr[2] & 0xffff;
                p_v6_128_snake_data->entry1_ipaddr2_16_31 = (ipv6_addr[2] >> 16) & 0xffff;
                p_v6_128_snake_mask->entry1_ipaddr2_0_15  = 0xffff;
                p_v6_128_snake_mask->entry1_ipaddr2_16_31 = 0xffff;

                p_v6_128_snake_data->entry1_ipaddr3_0_4   = ipv6_addr[3] & 0x1f;
                p_v6_128_snake_data->entry1_ipaddr3_5_31  = (ipv6_addr[3] >> 5) & 0x7ffffff;
                p_v6_128_snake_mask->entry1_ipaddr3_0_4   = 0x1f;
                p_v6_128_snake_mask->entry1_ipaddr3_5_31  = 0x7ffffff;

                p_v6_128_snake_data->entry1_masklen_0_7   = p_route_info->route_masklen;
                p_v6_128_snake_mask->entry1_masklen_0_7   = 0xff;
            }
            p_v6_128_snake_data->entry1_nexthop_0_4  = p_route_info->ad_idx & 0x1f;
            p_v6_128_snake_data->entry1_nexthop_5_17 = (p_route_info->ad_idx >> 5) & 0x1fff;
            p_v6_128_snake_mask->entry1_nexthop_0_4  = 0x1f;
            p_v6_128_snake_mask->entry1_nexthop_5_17 = 0x1fff;
        break;
        default:
        break;
    }
}
#endif
int32
_sys_nalpm_clear_sram(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, uint8 snake_idx, uint8 offset, uint8 clear_snake_type, void* p_data, void* p_data_mask)
{
    sys_nalpm_route_info_t*   p_route_info_void = NULL;


    int32 ret = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    p_route_info_void = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(p_tcam_item->p_prefix_info->ip_ver));
    if(!p_route_info_void)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_route_info_void, 0 , (ROUTE_INFO_SIZE(p_tcam_item->p_prefix_info->ip_ver)));
    p_route_info_void->ip_ver = p_tcam_item->p_prefix_info->ip_ver;
    p_route_info_void->route_masklen = 0;

    CTC_ERROR_GOTO(_sys_nalpm_write_sram(lchip, p_tcam_item, p_route_info_void, snake_idx, offset, 0 , p_data, p_data_mask), ret, error0);

    mem_free(p_route_info_void);


    return CTC_E_NONE;

error0:
    mem_free(p_route_info_void);
    return ret;
}

int32
_sys_tsingma_nalpm_lkup_entry(uint8 lchip,
                               sys_nalpm_route_info_t* p_route_info,
                               sys_nalpm_route_store_info_t* p_lkp_rlt,
                               sys_nalpm_prefix_trie_payload_t * p_prefix_trie_payload)
{
    uint8 i = 0, j = 0, void_i = 0, void_j = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 find_void_position = 0;
    uint8 sram_type = 0;
    uint32 sram_idx = 0;

    sram_type =  p_prefix_trie_payload->tcam_item.sram_type;
    sram_idx = p_prefix_trie_payload->tcam_item.sram_idx;

    SYS_NALPM_BUCKET_TRANVAS(lchip, i,sram_type, sram_idx, route_per_snake, snake_entry_cnt)
    {
        if (NALPM_BUCKET(lchip, sram_idx).bitmap[i] == 0)
        {
            if (!find_void_position)
            {
                find_void_position = 1;
                void_i = i;
                void_j = 0;
            }

            continue;
        }

        for (j = 0; j < snake_entry_cnt; j++)
        {
            if (p_prefix_trie_payload->tcam_item.p_ipuc_info_array[i][j])
            {
                /*entry exist, find exact route*/
                if (0 == _sys_tsingma_nalpm_route_cmp(p_route_info, p_prefix_trie_payload->tcam_item.p_ipuc_info_array[i][j]))
                {
                    p_lkp_rlt->sram_hit = TRUE;
                    p_lkp_rlt->snake_idx = i;
                    p_lkp_rlt->entry_offset = j;
                    break;
                }
            }
            else if( (!CTC_IS_BIT_SET(NALPM_BUCKET(lchip, sram_idx).bitmap[i], j)) && (!find_void_position))
            {
               /*entry not exist*/
               find_void_position = 1;
               void_i = i;
               void_j = j;
            }
        }
    }

    if (p_lkp_rlt->sram_hit == FALSE) /*not found*/
    {
        if (find_void_position)
        {
            p_lkp_rlt->snake_idx = void_i;
            p_lkp_rlt->entry_offset = void_j;
        }
    }

    return CTC_E_NONE;

}

int32
_sys_tsingma_nalpm_route_lkp(uint8 lchip, sys_nalpm_route_info_t* p_route_info, sys_nalpm_route_store_info_t* p_lkp_rlt)
{
    int32 ret = CTC_E_NONE;

    sys_nalpm_prefix_trie_payload_t * p_prefix_trie_payload = NULL;
    trie_node_t* p_node = NULL;

    uint32 * p_trie_key = NULL;


    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if(NULL == g_sys_nalpm_master[lchip]->prefix_trie[p_route_info->ip_ver][p_route_info->vrf_id])
    {
        return CTC_E_NOT_EXIST;
    }

    p_trie_key = mem_malloc(MEM_IPUC_MODULE, IP_ADDR_SIZE(p_route_info->ip_ver));
    if(!p_trie_key)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_trie_key, 0 ,(IP_ADDR_SIZE(p_route_info->ip_ver)));
    sal_memcpy(p_trie_key, p_route_info->ip, (IP_ADDR_SIZE(p_route_info->ip_ver)));

    ret = sys_nalpm_trie_find_lpm (g_sys_nalpm_master[lchip]->prefix_trie[p_route_info->ip_ver][p_route_info->vrf_id], p_trie_key,
                                            p_route_info->route_masklen, &p_node, 1);
    if(ret || p_node == NULL)
    {
        ret = ret? ret : CTC_E_NOT_EXIST;
        goto END;
    }
    p_prefix_trie_payload =(sys_nalpm_prefix_trie_payload_t*)p_node;
    p_lkp_rlt->tcam_hit = TRUE;
    p_lkp_rlt->p_tcam_item = &p_prefix_trie_payload->tcam_item;
    p_lkp_rlt->sram_hit= FALSE;
    p_lkp_rlt->total_skip_len = p_node->total_skip_len;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)    prefix len[%u], tcam_idx=[%u] \n",
                    __LINE__, p_lkp_rlt->p_tcam_item->p_prefix_info->tcam_masklen, p_lkp_rlt->p_tcam_item->tcam_idx);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)    total skip len[%u] \n",
                    __LINE__, p_lkp_rlt->total_skip_len);

    CTC_ERROR_GOTO(_sys_tsingma_nalpm_lkup_entry(lchip, p_route_info, p_lkp_rlt, p_prefix_trie_payload), ret, END);


END:
    if(p_trie_key)
    {
        mem_free(p_trie_key);
    }

    return ret;
}

int32
_sys_tsingma_nalpm_read_tcam(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, uint32* p_ad_idx)
{
    uint8 ip_ver = p_tcam_item->p_prefix_info->ip_ver;
    sys_ipuc_tcam_ad_t ad;
    int32 ret = CTC_E_NONE;

    sal_memset(&ad, 0 , sizeof(ad));
    ad.tcamAd_key_idx = p_tcam_item->tcam_idx;
    CTC_ERROR_RETURN(sys_tsingma_ipuc_tcam_read_ad( lchip,  ip_ver,  SYS_PRIVATE_MODE, &ad));
    *p_ad_idx = ad.nexthop;

    return ret;
}

int32
_sys_tsingma_nalpm_write_tcam(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, sys_ipuc_opt_type_t opt, uint32 update_ad_idx)
{
    sys_ipuc_tcam_key_t key;
    sys_ipuc_tcam_ad_t ad;
    uint8 ip_ver = p_tcam_item->p_prefix_info->ip_ver;
    int32 ret = CTC_E_NONE;

    if(DO_ADD == opt || DO_UPDATE == opt)
    {
        sal_memset(&ad, 0 , sizeof(ad));
        ad.tcamAd_key_idx = p_tcam_item->tcam_idx;
        ad.lpmPipelineValid = 1;
        if(DRV_IS_TSINGMA(lchip))
        {

            if(p_tcam_item->p_prefix_info->ip_ver)
            {
                if(p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_64)
                {
                    ad.lpmStartByte = SYS_NALPM_SRAM_TYPE_V6_64;
                }
                else
                {
                    ad.lpmStartByte = SYS_NALPM_SRAM_TYPE_V6_128;
                }
            }
            else
            {
                ad.lpmStartByte = SYS_NALPM_SRAM_TYPE_V4_32;
            }
        }
        ad.pointer = (p_tcam_item->sub_bkt << 16) | (p_tcam_item->sram_idx);
        ad.nexthop = (DO_UPDATE == opt)? update_ad_idx : p_tcam_item->p_prefix_info->ad_idx;
        p_tcam_item->p_prefix_info->ad_idx = ad.nexthop;

        CTC_ERROR_RETURN(sys_tsingma_ipuc_tcam_write_ad2hw( lchip,  ip_ver,  SYS_PRIVATE_MODE, &ad, opt));
    }

    if(opt != DO_UPDATE)
    {
        uint32 t = 0;
        sal_memset(&key, 0 , sizeof(key));
        sal_memcpy(&key.ip, p_tcam_item->p_prefix_info->ip,  IP_ADDR_SIZE(ip_ver));
        key.key_idx = p_tcam_item->tcam_idx;
        if(ip_ver == CTC_IP_VER_4)
        {
            SYS_NALPM_CONVERT_TO_MSB(p_tcam_item->p_prefix_info->ip, p_tcam_item->p_prefix_info->tcam_masklen, &key.ip.ipv4, CTC_IP_VER_4);
        }
        else
        {
            SYS_NALPM_CONVERT_TO_MSB(p_tcam_item->p_prefix_info->ip, p_tcam_item->p_prefix_info->tcam_masklen, key.ip.ipv6, CTC_IP_VER_6);
        }
        key.mask_len = p_tcam_item->p_prefix_info->tcam_masklen;
        key.vrfId = p_tcam_item->p_prefix_info->vrf_id;
        key.vrfId_mask =  0x1FFF;

        if (ip_ver == CTC_IP_VER_6)
        {
            if (IS_SHORT_KEY(SYS_PRIVATE_MODE, key.key_idx))
            {
                t = key.ip.ipv6[0];
                key.ip.ipv6[0] = key.ip.ipv6[1];
                key.ip.ipv6[1] = t;
            }
            else
            {
                t = key.ip.ipv6[0];
                key.ip.ipv6[0] = key.ip.ipv6[3];
                key.ip.ipv6[3] = t;

                t = key.ip.ipv6[1];
                key.ip.ipv6[1] = key.ip.ipv6[2];
                key.ip.ipv6[2] = t;
            }
        }

        CTC_ERROR_RETURN(sys_tsingma_ipuc_tcam_write_key2hw( lchip,  ip_ver,  SYS_PRIVATE_MODE, &key, opt));
    }

    return ret;
}

int32
_sys_tsingma_nalpm_route_vrf_init(uint8 lchip, ctc_ipuc_param_t*  p_ipuc_param)
{
    uint16 sram_idx = 0;
    uint8  ip_ver = 0;
    uint16 vrf_id = 0;
    uint32 pfx_len = 0;
    sys_nalpm_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm_prefix_trie_payload_t* p_prefix_payload = NULL;
    uint32 pfx[4] = {0};
    trie_t *prefix_trie = NULL;
    sys_nalpm_route_info_t* p_pfx_info = NULL;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1, 1);
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;
    p_prefix_payload = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_prefix_trie_payload_t));
    if(NULL == p_prefix_payload)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_prefix_payload, 0, sizeof(sys_nalpm_prefix_trie_payload_t));
    p_tcam_item =  &(p_prefix_payload->tcam_item);

    p_pfx_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_pfx_info)
    {
        ret =  CTC_E_NO_MEMORY;
        goto error1;
    }
    sal_memset(p_pfx_info, 0, ROUTE_INFO_SIZE(ip_ver));
    p_pfx_info->ip_ver = ip_ver;
    p_pfx_info->vrf_id = vrf_id;
     /*p_pfx_info->ad_idx = p_usw_ipuc_master[lchip]->default_base[ip_ver];*/
    p_pfx_info->ad_idx = INVALID_DRV_NEXTHOP_OFFSET;
    p_tcam_item->p_prefix_info = p_pfx_info;
    CTC_ERROR_GOTO(_sys_tsingma_nalpm_tcam_idx_alloc(lchip, p_ipuc_param, p_tcam_item),ret, error0);
    CTC_ERROR_GOTO(_sys_tsingma_nalpm_sram_idx_alloc(lchip, ip_ver, &sram_idx, &p_tcam_item->sub_bkt, 1), ret, error1);
    p_tcam_item->sram_idx = sram_idx;
    p_tcam_item->p_AD_route = NULL;
    NALPM_BUCKET(lchip, sram_idx).is_root = 1;

    _sys_tsingma_nalpm_set_sram_type(lchip, ip_ver, p_ipuc_param->masklen, p_tcam_item);
    /*add to prefix trie*/

    /*add to prefix trie*/
    CTC_ERROR_GOTO(sys_nalpm_trie_init ((CTC_IP_VER_4 == ip_ver)? SYS_NALPM_V4_MASK_LEN_MAX : SYS_NALPM_V6_MASK_LEN_MAX,
                                    &(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id])),
                   ret, error2);

    prefix_trie = g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id];
    CTC_ERROR_GOTO(sys_nalpm_trie_insert (prefix_trie, pfx, NULL, pfx_len, (trie_node_t *) p_prefix_payload, 0), ret, error3);

    CTC_ERROR_GOTO(sys_nalpm_trie_init (CTC_IP_VER_4 == ip_ver? SYS_NALPM_V4_MASK_LEN_MAX : SYS_NALPM_V6_MASK_LEN_MAX, &p_tcam_item->trie),ret, error4);

    /*clear snake*/
    {
        sys_nalpm_cookie_t *p_cookie;
        p_cookie =  mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_cookie_t));
        if (!p_cookie)
        {
            ret =  CTC_E_NO_MEMORY;
            goto error5;
        }

        sal_memset(p_cookie, 0, sizeof(sys_nalpm_cookie_t));

        _sys_tsingma_nalpm_write_route_cookie(lchip, p_tcam_item, NULL, p_cookie);

        mem_free(p_cookie);
    }

    CTC_ERROR_GOTO(_sys_tsingma_nalpm_write_tcam( lchip, p_tcam_item, DO_ADD, 0), ret, error5);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)    p_prefix_payload [%p]\n",__LINE__, p_prefix_payload);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)    p_tcam_item [%p]\n", __LINE__, p_tcam_item);


#ifdef IPUC_TEST_STUB
    /*add to prefix trie*/
    sys_nalpm_trie_init ((CTC_IP_VER_4 == ip_ver)? SYS_NALPM_V4_MASK_LEN_MAX : SYS_NALPM_V6_MASK_LEN_MAX,
                                    &(g_sys_nalpm_master[lchip]->route_db_trie[ip_ver][vrf_id]));
#endif

    return ret;

error5:
    sys_nalpm_trie_destroy(p_tcam_item->trie);
error4:
    sys_nalpm_trie_delete(prefix_trie, pfx, pfx_len, (trie_node_t * *) &p_prefix_payload,  0);
error3:
    sys_nalpm_trie_destroy(prefix_trie);
    g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id] = NULL;
error2:
    _sys_tsingma_nalpm_sram_idx_free( lchip,  sram_idx, ip_ver);
error1:
    _sys_tsingma_nalpm_tcam_idx_free( lchip, p_ipuc_param, p_tcam_item);
error0:
    if(p_prefix_payload)
        mem_free(p_prefix_payload);
    if(p_pfx_info)
        mem_free(p_pfx_info);

    return ret;
}

int32
_sys_tsingma_nalpm_route_vrf_deinit(uint8 lchip, ctc_ipuc_param_t*  p_ipuc_param)
{
    sys_nalpm_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm_prefix_trie_payload_t * p_pfx_payload = NULL;
    uint32 pfx_len = 0;
    uint32 pfx[4] = {0};
    trie_t* vrf_trie;
    uint8  ip_ver = 0;
    uint16 vrf_id = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1, 1);
    /* prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;

    vrf_trie = g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id];
    p_pfx_payload = CONTAINER_OF(vrf_trie->trie, sys_nalpm_prefix_trie_payload_t, node);
    p_tcam_item = &p_pfx_payload->tcam_item;

    CTC_ERROR_RETURN(_sys_tsingma_nalpm_tcam_idx_free(lchip, p_ipuc_param, p_tcam_item));

    CTC_ERROR_RETURN(_sys_tsingma_nalpm_sram_idx_free(lchip, p_tcam_item->sram_idx, ip_ver));

    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(p_tcam_item->trie));
    /*pfx trie*/
    vrf_trie = g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id];
    CTC_ERROR_RETURN(sys_nalpm_trie_delete (vrf_trie, pfx, pfx_len, (trie_node_t **)&p_pfx_payload, 0));
    if (NULL != vrf_trie->trie)  /* sram entry is empty, release tcam*/
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "---[%d]---\n",__LINE__);
        return CTC_E_UNEXPECT;
    }
    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(vrf_trie));
    CTC_ERROR_RETURN(_sys_tsingma_nalpm_write_tcam(lchip, p_tcam_item, DO_DEL, 0));
    g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id] = NULL;

#ifdef IPUC_TEST_STUB
    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(g_sys_nalpm_master[lchip]->route_db_trie[ip_ver][vrf_id]));
    g_sys_nalpm_master[lchip]->route_db_trie[ip_ver][vrf_id] = NULL;

#endif

    mem_free(p_pfx_payload->tcam_item.p_prefix_info);
    mem_free(p_pfx_payload);
    return CTC_E_NONE;
}



STATIC int32
_sys_tsingma_nalpm_sram_entry_is_full(uint8 lchip, sys_nalpm_tcam_item_t *p_tcam_item, sys_nalpm_route_info_t*  p_route_info)
{
    uint8 i = 0;

    if (NALPM_BUCKET_MGR_EN(lchip, p_route_info->ip_ver))
    {
        for (i = 0; i < NALPM_BUKCET_SNAKE_NUM(lchip); i++)
        {
            if (NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[i] != 0x3F)
            {
                return FALSE;
            }
        }
    }
    else
    {
        if (p_tcam_item->trie->trie == NULL ||
            p_tcam_item->trie->trie->count <= _sys_tsingma_nalpm_get_bucket_entry_cnt(lchip, p_tcam_item->sram_type))
        {
            return FALSE;
        }
    }

    return TRUE;
}




int32
_sys_tsingma_nalpm_route_install_element (trie_node_t * node, void *data)
{
    uint8 i = 0, j = 0,  hw_i = 0, hw_j = 0;
    sys_nalpm_cookie_t* p_cookie = data;
    sys_nalpm_tcam_item_t* p_tcam_item = p_cookie->p_install_tcam;
    uint8 lchip = p_cookie->lchip;
    sys_nalpm_route_info_t* p_route_info = NULL;
    sys_nalpm_trie_payload_t* p_payload = CONTAINER_OF(node, sys_nalpm_trie_payload_t, node);


    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if (node->type != PAYLOAD)
    {
        return CTC_E_NONE;
    }
    p_route_info = p_payload->p_route_info;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "p_payload=[%p], node = [%p],p_route_info=[%p]\n", p_payload, node , p_route_info);

    hw_i = p_route_info->hw_position[0];
    hw_j = p_route_info->hw_position[1];

    if (p_cookie->merge_cnt)
    {
        if (p_tcam_item->p_ipuc_info_array[hw_i][hw_j] != p_route_info)
        {
            /*clear old*/
            CTC_BIT_UNSET(NALPM_BUCKET(lchip, p_cookie->p_chd_tcam->sram_idx).bitmap[hw_i], hw_j);

            /*merge new*/
            i = (p_cookie->index_array[p_cookie->cur_idx] >> 8);
            j = (p_cookie->index_array[p_cookie->cur_idx++] & 0xFF);
            p_tcam_item->p_ipuc_info_array[i][j] = p_route_info;
            CTC_BIT_SET(NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[i], j);
            p_route_info->hw_position[0] = i;
            p_route_info->hw_position[1] = j;
        }

    }
    else if (p_cookie->new_tcam)
    {
        if (hw_i == 0xFF && hw_j == 0xFF )
        {
            p_cookie->p_new_route = p_route_info;
            p_cookie->route_in_new_trie = 1;
        }
        else
        {
            p_cookie->clear_array[p_cookie->clear_cnt++] = (hw_i << 8 | hw_j);
        }

        i = (p_cookie->index_array[p_cookie->cur_idx] >> 8);
        j = (p_cookie->index_array[p_cookie->cur_idx++] & 0xFF);

        p_tcam_item->p_ipuc_info_array[i][j] = p_route_info;
        CTC_BIT_SET(NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[i], j);
        p_route_info->hw_position[0] = i;
        p_route_info->hw_position[1] = j;

        p_route_info->ipuc_info->tcam_idx = p_tcam_item->tcam_idx;
        p_route_info->ipuc_info->snake_idx = i;
        p_route_info->ipuc_info->entry_offset = j;

        _sys_nalpm_write_sram(lchip, p_tcam_item, p_route_info, i , j, 0, p_cookie->ds_snake_split[i], p_cookie->ds_snake_split_mask[i]);

    }
    else
    {
        if (hw_i == 0xFF &&  hw_j == 0xFF )
        {
            p_cookie->p_new_route = p_route_info;
        }
    }

    return CTC_E_NONE;
}


int32
_sys_tsingma_nalpm_reinstall_element (uint8 lchip,
                                                sys_nalpm_tcam_item_t* p_tcam_item,
                                                sys_nalpm_cookie_t* p_cookie)

{
    uint8 i  = 0;
    uint8 j = 0;
    uint8 idx = 0;
    uint8 do_compact_op = 0;
    sys_nalpm_route_info_t* p_new_route = NULL;
    uint8 ip_ver = p_tcam_item->p_prefix_info->ip_ver;


    for (idx = 0; idx < p_cookie->clear_cnt; idx++)
    {
        i = (p_cookie->clear_array[idx] >> 8);
        j = (p_cookie->clear_array[idx]& 0xFF);
        p_tcam_item->p_ipuc_info_array[i][j] = NULL;
        CTC_BIT_UNSET(NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[i], j);

        if (NALPM_SNAKE_IS_COMPACT(lchip, p_tcam_item->sram_type, i))
        {
             do_compact_op = 1;
        }
        else
        {
            _sys_nalpm_clear_sram(lchip, p_tcam_item, i, j, 0, p_cookie->ds_snake_root[i], p_cookie->ds_snake_root_mask[i]);
        }
    }

    p_new_route = p_cookie->p_new_route;

    if (!p_cookie->route_in_new_trie && p_new_route->hw_position[0] == 0xff)
    {
        _sys_tsingma_nalpm_find_best_position(lchip, p_tcam_item, 0, &i, &j);

        if(i != 0xff && j!= 0xff)
        {
        p_tcam_item->p_ipuc_info_array[i][j] = p_new_route;
        p_new_route->hw_position[0] = i;
        p_new_route->hw_position[1] = j;
        CTC_BIT_SET(NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[i], j);

        if (NALPM_SNAKE_IS_COMPACT(lchip, p_tcam_item->sram_type, i))
        {
            do_compact_op = 1;
        }
        else
        {
            _sys_nalpm_write_sram(lchip, p_tcam_item, p_new_route, i , j, 0, p_cookie->ds_snake_root[i], p_cookie->ds_snake_root_mask[i]);
        }
        }
    }


    if (ip_ver == CTC_IP_VER_6 && do_compact_op && g_sys_nalpm_master[lchip]->v6_mode)
    {
        _sys_tsingma_nalpm_do_compact(lchip, p_tcam_item, p_cookie);
    }


    return CTC_E_NONE;
}





STATIC int32
_sys_tsingma_nalpm_alloc_offset_array(uint8 lchip,
                                sys_nalpm_tcam_item_t* p_tcam_item,
                                sys_nalpm_cookie_t* p_cookie)
{
    uint32 sram_idx = 0;
    uint8 i = 0, j = 0;
    uint8 idx = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 stop_cnt = 0;

    sram_idx = p_tcam_item->sram_idx;
    stop_cnt = p_cookie->merge_cnt?p_cookie->merge_cnt: p_tcam_item->trie->trie->count;


    SYS_NALPM_BUCKET_TRANVAS(lchip, i, p_tcam_item->sram_type, sram_idx, route_per_snake, snake_entry_cnt)
    {
        if (NALPM_BUCKET(lchip, sram_idx).bitmap[i]
            == _sys_nalpm_get_snake_bitwdith(lchip, p_tcam_item->sram_type, i))
        {
            continue;
        }

        for (j = 0; j < snake_entry_cnt; j++)
        {
            if (CTC_IS_BIT_SET(NALPM_BUCKET(lchip, sram_idx).bitmap[i], j))
            {
                continue;
            }

            p_cookie->index_array[idx++] = (i << 8 | j);

            if (idx == stop_cnt)
            {
                return 0;
            }
        }
    }


    return 0;
}


STATIC int32
_sys_tsingma_nalpm_renew_route_trie(uint8 lchip,
                                  sys_nalpm_tcam_item_t* p_tcam_item,
                                  sys_nalpm_cookie_t* p_cookie,
                                  uint8 new_tcam)
{
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    p_cookie->lchip = lchip;
    p_cookie->new_tcam = new_tcam;
    p_cookie->p_install_tcam = p_tcam_item;

    if(new_tcam)
    {
        sal_memset(p_tcam_item->p_ipuc_info_array, 0 , sizeof(p_tcam_item->p_ipuc_info_array));
    }

    CTC_ERROR_RETURN(sys_nalpm_trie_traverse (p_tcam_item->trie->trie,
                                              _sys_tsingma_nalpm_route_install_element,
                                              (void*)p_cookie,
                                              _TRIE_INORDER_TRAVERSE));
    return ret;
}


STATIC int32
_sys_tsingma_nalpm_merge_route_trie(uint8 lchip,
                                  uint16 merge_cnt,
                                  sys_nalpm_tcam_item_t* p_prt_tcam_item,
                                  sys_nalpm_tcam_item_t* p_chd_tcam_item)
{
    int32 ret = CTC_E_NONE;
    sys_nalpm_cookie_t* cookie;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    cookie = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_cookie_t));
    if(NULL == cookie)
    {
        return CTC_E_NO_MEMORY;
    }
    /*prepare cookie data*/
    sal_memset(cookie, 0, sizeof(sys_nalpm_cookie_t));

    /*alloc offset*/
    cookie->merge_cnt =  merge_cnt;
    _sys_tsingma_nalpm_alloc_offset_array(lchip, p_prt_tcam_item, cookie);

    cookie->lchip = lchip;
    cookie->p_install_tcam = p_prt_tcam_item;
    cookie->p_chd_tcam = p_chd_tcam_item;

    ret = (sys_nalpm_trie_traverse (p_prt_tcam_item->trie->trie,
                                              _sys_tsingma_nalpm_route_install_element,
                                              (void*)cookie,
                                              _TRIE_INORDER_TRAVERSE));
    mem_free(cookie);
    return ret;
}

int32
_sys_tsingma_nalpm_write_route_trie(uint8 lchip,sys_nalpm_tcam_item_t* p_tcam_item, uint8 new_tcam)
{
    uint8 i = 0, j = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;

    uint8 do_compact_op = 0;
    uint8 ip_ver = p_tcam_item->p_prefix_info->ip_ver;
    sys_nalpm_cookie_t* p_cookie = NULL;
    sys_nalpm_route_info_t* p_new_route = NULL;

    /*prepare cookie data*/
    _sys_tsingma_nalpm_create_cookie(lchip, p_tcam_item, NULL, &p_cookie);

    SYS_NALPM_BUCKET_LOOP(lchip, i, p_tcam_item->sram_type, p_tcam_item->sram_idx, route_per_snake, snake_entry_cnt)
    {
        for (j = 0; j < snake_entry_cnt; j++)
        {
            if (NULL == p_tcam_item->p_ipuc_info_array[i][j])
            {
                continue;
            }

            p_new_route = p_tcam_item->p_ipuc_info_array[i][j] ;

            if (NALPM_SNAKE_IS_COMPACT(lchip, p_tcam_item->sram_type, i))
            {
                do_compact_op = 1;
            }
            else
            {
                _sys_nalpm_write_sram(lchip, p_tcam_item, p_new_route, i , j, 0, p_cookie->ds_snake_root[i], p_cookie->ds_snake_root_mask[i]);
            }
        }
    }

    if (ip_ver == CTC_IP_VER_6 && do_compact_op && g_sys_nalpm_master[lchip]->v6_mode)
    {
        _sys_tsingma_nalpm_do_compact(lchip, p_tcam_item, p_cookie);
    }

    /*write cookie data to hw*/
    _sys_tsingma_nalpm_write_route_cookie(lchip, p_tcam_item, NULL, p_cookie);

    mem_free(p_cookie);

    return 0;

};



int32
_sys_tsingma_nalpm_search_best_route_in_sram(uint8 lchip, trie_node_t *p_prefix_node, sys_nalpm_route_info_t* p_pfx_route,sys_nalpm_route_info_t** pp_best_route)
{
    int32 ret = CTC_E_NONE;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 best_snake = 0xff;
    uint8 best_offset = 0xff;
    uint8 i = 0, j = 0;
    sys_nalpm_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm_prefix_trie_payload_t * p_prefix_trie_payload = CONTAINER_OF(p_prefix_node, sys_nalpm_prefix_trie_payload_t, node);

    *pp_best_route = NULL;
    p_tcam_item = &(p_prefix_trie_payload->tcam_item);

    if(p_tcam_item->p_prefix_info->tcam_masklen && p_tcam_item->p_AD_route)
    {
        if(0 == _sys_tsingma_nalpm_route_match(lchip, p_pfx_route, p_tcam_item->p_AD_route))
        {
            *pp_best_route = p_tcam_item->p_AD_route;
        }
    }

    SYS_NALPM_BUCKET_LOOP(lchip, i, p_tcam_item->sram_type, p_tcam_item->sram_idx, route_per_snake, snake_entry_cnt)
    {
        for (j = 0; j < snake_entry_cnt; j++)
        {
            if (NULL != p_tcam_item->p_ipuc_info_array[i][j])
            {
                if (_sys_tsingma_nalpm_route_match(lchip, p_pfx_route, p_tcam_item->p_ipuc_info_array[i][j]))
                {
                    continue;
                }
                if (0xff == best_snake
                || p_tcam_item->p_ipuc_info_array[i][j]->route_masklen > p_tcam_item->p_ipuc_info_array[best_snake][best_offset]->route_masklen)
                {
                    best_snake = i;
                    best_offset = j;
                }
            }
        }
    }
    if(best_snake != 0xff)
    {
        (*pp_best_route) = p_tcam_item->p_ipuc_info_array[best_snake][best_offset];
    }
    return ret;
}

int32
_sys_tsingma_nalpm_update_longer_pfx_AD_add(trie_node_t* p_longer_pfx_node,void* data)
{
    int32 ret = CTC_E_NONE;
    sys_nalpm_route_and_lchip_t* route_and_lchip = (sys_nalpm_route_and_lchip_t*) data;
    uint8 lchip = route_and_lchip->lchip;
    uint32 hw_idx = 0;
    sys_nalpm_route_info_t* p_new_route = route_and_lchip->p_route;
    sys_nalpm_prefix_trie_payload_t * p_prefix_trie_payload = NULL;
    uint8 hit = 0;

    p_prefix_trie_payload = CONTAINER_OF(p_longer_pfx_node, sys_nalpm_prefix_trie_payload_t, node);
    if(route_and_lchip->ageing_opt == IPUC_LPM_AGING_NONE)
    {
        if (p_prefix_trie_payload->tcam_item.p_AD_route == NULL
            || p_prefix_trie_payload->tcam_item.p_AD_route->route_masklen <= p_new_route->route_masklen)
        {
            p_prefix_trie_payload->tcam_item.p_AD_route = p_new_route;
            CTC_ERROR_RETURN(_sys_tsingma_nalpm_write_tcam( lchip, &(p_prefix_trie_payload->tcam_item), DO_UPDATE, p_new_route->ad_idx));
        }

    }
    else if(p_new_route == p_prefix_trie_payload->tcam_item.p_AD_route)/*aging*/
    {
        route_and_lchip->is_covered = 1;
        //hw_idx = sys_tsingma_nalpm_get_hw_sram_idx(lchip, &p_prefix_trie_payload->tcam_item, p_new_route->hw_position[0]);

        hw_idx = p_prefix_trie_payload->tcam_item.tcam_idx;
        if(route_and_lchip->ageing_opt == IPUC_LPM_AGING_GET)
        {
            CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_aging_status(lchip, SYS_AGING_DOMAIN_TCAM, hw_idx, &hit));
            route_and_lchip->ageing_bit = (hit == 1) ? 1 : route_and_lchip->ageing_bit;

        }
        else
        {
            CTC_ERROR_RETURN(MCHIP_LA(lchip)->set_aging_status(lchip, SYS_AGING_DOMAIN_TCAM, hw_idx, 0, route_and_lchip->ageing_bit));
        }
    }

    return ret;
}

int32
_sys_tsingma_nalpm_add_route_cover(uint8 lchip,sys_nalpm_tcam_item_t* p_tcam_item,sys_nalpm_route_info_t* p_new_route,
                                    uint32 nh_id, uint32 total_skip_len, uint8 ageing_opt, uint8 *p_hit)
{
    int32 ret = CTC_E_NONE;
    trie_node_t* p_prefix_node = NULL;
    sys_nalpm_route_and_lchip_t route_and_lchip;
    sys_nalpm_prefix_trie_payload_t* p_prefix_trie_payload = NULL;
    uint32 key[4] =  {0};
    uint8 length = 0;
    sal_memset(&route_and_lchip, 0, sizeof(sys_nalpm_route_and_lchip_t));

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1, 1);

    sal_memset(&route_and_lchip, 0, sizeof(route_and_lchip));
    route_and_lchip.lchip = lchip;
    route_and_lchip.p_route = p_new_route;
    route_and_lchip.nh_id = nh_id;
    route_and_lchip.prefix_len = total_skip_len;
    route_and_lchip.ageing_opt = ageing_opt;
    if(ageing_opt == IPUC_LPM_AGING_SET) /*set*/
    {
        route_and_lchip.ageing_bit = *p_hit;
    }

    /*find trie node of  current tcam_pfx from prefix_trie */
    p_prefix_trie_payload = CONTAINER_OF(p_tcam_item, sys_nalpm_prefix_trie_payload_t, tcam_item);
    p_prefix_node = &(p_prefix_trie_payload->node);


    sal_memcpy(key, p_new_route->ip, (IP_ADDR_SIZE(p_new_route->ip_ver)));
    length = p_new_route->route_masklen;

    if (p_new_route->ip_ver == 0)
    {
        SYS_NALPM_CONVERT_TO_LSB(key, length, p_new_route->ip_ver);
        ret = sys_nalpm_trie_propagate_prefix(p_prefix_node,
                                              key, length  + p_prefix_node->skip_len - total_skip_len,
                                              _sys_tsingma_nalpm_update_longer_pfx_AD_add,
                                              (void *)&route_and_lchip, 1);
    }
    else
    {
        SYS_NALPM_CONVERT_TO_LSB(key, length, p_new_route->ip_ver);
        ret = sys_nalpm_v6_trie_propagate_prefix(p_prefix_node,
                                              key, length  + p_prefix_node->skip_len - total_skip_len,
                                              _sys_tsingma_nalpm_update_longer_pfx_AD_add,
                                              (void *)&route_and_lchip, 1);
    }


    if (IPUC_LPM_AGING_NONE == route_and_lchip.ageing_opt)
    {
        return ret;
    }
    if (route_and_lchip.is_covered == 1)
    {
        if (route_and_lchip.ageing_opt == IPUC_LPM_AGING_GET)
        {
            *p_hit = route_and_lchip.ageing_bit;
        }
    }


    return ret;
}


int32
_sys_tsingma_nalpm_update_longer_pfx_AD_del(trie_node_t* p_longer_pfx_node,void* data)
{
    int32 ret = CTC_E_NONE;
    sys_nalpm_route_and_lchip_t* p_route_and_lchip = (sys_nalpm_route_and_lchip_t*)data;
    uint8 lchip = p_route_and_lchip->lchip;
    sys_nalpm_route_info_t * p_del_route = p_route_and_lchip->p_route;
    sys_nalpm_prefix_trie_payload_t * p_prefix_trie_payload = NULL;
    sys_nalpm_prefix_trie_payload_t * p_root_payload = NULL;
    trie_node_t * p_father_node = NULL;
    trie_t *prefix_trie = NULL;
    sys_nalpm_route_info_t* p_best_route = NULL;
    uint32 ad_idx = INVALID_DRV_NEXTHOP_OFFSET;


    if(p_longer_pfx_node->type  != PAYLOAD)
    {
        return ret;
    }

    p_prefix_trie_payload = CONTAINER_OF(p_longer_pfx_node, sys_nalpm_prefix_trie_payload_t, node);
    ret = _sys_tsingma_nalpm_route_match(lchip, p_prefix_trie_payload->tcam_item.p_prefix_info, p_del_route);
    if (0 != ret)
    {
        return ret;
    }

    if(p_prefix_trie_payload->tcam_item.p_prefix_info->tcam_masklen && 
        0 != _sys_tsingma_nalpm_route_cmp(p_prefix_trie_payload->tcam_item.p_AD_route, p_del_route))
    {
        return ret;
    }

    prefix_trie = g_sys_nalpm_master[lchip]->prefix_trie[p_del_route->ip_ver][p_del_route->vrf_id];
    p_father_node = p_route_and_lchip->p_father;
    if(NULL == p_father_node)
    {
        return ret;
    }

    CTC_ERROR_RETURN(_sys_tsingma_nalpm_search_best_route_in_sram(lchip, p_father_node, p_prefix_trie_payload->tcam_item.p_prefix_info, &p_best_route));
    p_prefix_trie_payload->tcam_item.p_AD_route = p_best_route;
    if (p_best_route)
    {
        CTC_ERROR_RETURN(_sys_tsingma_nalpm_write_tcam( lchip, &(p_prefix_trie_payload->tcam_item), DO_UPDATE, p_best_route->ad_idx));
    }
    else
    {
        p_root_payload = CONTAINER_OF(prefix_trie->trie, sys_nalpm_prefix_trie_payload_t, node);
        CTC_ERROR_RETURN(_sys_tsingma_nalpm_read_tcam(lchip, &p_root_payload->tcam_item, &ad_idx));
        CTC_ERROR_RETURN(_sys_tsingma_nalpm_write_tcam( lchip, &(p_prefix_trie_payload->tcam_item), DO_UPDATE, ad_idx));
    }

    return ret;
}

int32
_sys_tsingma_nalpm_deletes_route_cover(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t* p_del_route, uint32 total_skip_len)
{
    int32 ret = CTC_E_NONE;
    trie_node_t* p_prefix_node = NULL;
    sys_nalpm_route_and_lchip_t del_route_lchip;
    sys_nalpm_prefix_trie_payload_t* p_prefix_trie_payload = NULL;
    uint32 key[4] =  {0};
    uint8 length = 0;

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO, 1);

    /*find trie node of  current tcam_pfx from prefix_trie */
    p_prefix_trie_payload = CONTAINER_OF(p_tcam_item, sys_nalpm_prefix_trie_payload_t, tcam_item);
    p_prefix_node = &(p_prefix_trie_payload->node);
    del_route_lchip.prefix_len = total_skip_len;
    del_route_lchip.p_route = p_del_route;
    del_route_lchip.lchip = lchip;
    del_route_lchip.p_father = p_prefix_node;

    sal_memcpy(key, p_del_route->ip, (IP_ADDR_SIZE(p_del_route->ip_ver)));
    length = p_del_route->route_masklen;

    if (p_del_route->ip_ver == 0)
    {
        SYS_NALPM_CONVERT_TO_LSB(key, length, p_del_route->ip_ver);
        ret = sys_nalpm_trie_propagate_prefix(p_prefix_node,
                                              key, length  + p_prefix_node->skip_len - total_skip_len,
                                              _sys_tsingma_nalpm_update_longer_pfx_AD_del,
                                              (void *)&del_route_lchip, 1);
    }
    else
    {
        SYS_NALPM_CONVERT_TO_LSB(key, length, p_del_route->ip_ver);
        ret = sys_nalpm_v6_trie_propagate_prefix(p_prefix_node,
                                                 key, length  + p_prefix_node->skip_len - total_skip_len,
                                                 _sys_tsingma_nalpm_update_longer_pfx_AD_del,
                                                 (void *)&del_route_lchip, 1);
     }

    return ret;
}

int32
_sys_tsingma_nalpm_update_longer_pfx_AD_default(trie_node_t* p_longer_pfx_node,void* data)
{
    int32 ret = CTC_E_NONE;
    sys_nalpm_route_and_lchip_t* p_route_and_lchip = (sys_nalpm_route_and_lchip_t*)data;
    sys_nalpm_prefix_trie_payload_t * p_prefix_trie_payload = NULL;
    uint32 ad_idx = p_route_and_lchip->p_route->ad_idx;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = p_route_and_lchip->lchip;
#endif
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    if(p_longer_pfx_node->type  != PAYLOAD)
    {
        return ret;
    }

    p_prefix_trie_payload = CONTAINER_OF(p_longer_pfx_node, sys_nalpm_prefix_trie_payload_t, node);

    if(!p_prefix_trie_payload->tcam_item.p_prefix_info->tcam_masklen ||
        NULL == p_prefix_trie_payload->tcam_item.p_AD_route)
    {
        CTC_ERROR_RETURN(_sys_tsingma_nalpm_write_tcam(p_route_and_lchip->lchip, &(p_prefix_trie_payload->tcam_item), DO_UPDATE, ad_idx));
    }

    return ret;
}

int32
_sys_tsingma_nalpm_default_route_cover(uint8 lchip,uint8 ip_ver, uint16 vrf_id, uint32 ad_index)
{
    int32 ret = CTC_E_NONE;
    trie_node_t* p_prefix_node = NULL;
    sys_nalpm_route_and_lchip_t default_info;

    p_prefix_node = g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id]->trie;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO, 1);

    default_info.p_route = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == default_info.p_route)
    {
        return CTC_E_NO_MEMORY;
    }
    default_info.lchip = lchip;
    default_info.p_route->ad_idx = ad_index;
    default_info.p_route->ip_ver = ip_ver;
    default_info.p_route->vrf_id = vrf_id;

    if(p_prefix_node->child[0].child_node)
    {
        CTC_ERROR_GOTO(sys_nalpm_trie_traverse (p_prefix_node->child[0].child_node, _sys_tsingma_nalpm_update_longer_pfx_AD_default,(void *)&default_info, _TRIE_PREORDER_TRAVERSE), ret,error_proc);
    }

    if(p_prefix_node->child[1].child_node)
    {
        CTC_ERROR_GOTO(sys_nalpm_trie_traverse (p_prefix_node->child[1].child_node, _sys_tsingma_nalpm_update_longer_pfx_AD_default,(void *)&default_info, _TRIE_PREORDER_TRAVERSE), ret,error_proc);
    }

error_proc:
    mem_free(default_info.p_route);

    return ret;
}

int32
_sys_tsingma_nalpm_add_directly(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, sys_nalpm_route_info_t*  p_route_info, sys_nalpm_route_store_info_t *p_lkp_rlt, uint32 nh_id)
{

    int32 ret = CTC_E_NONE;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);


    p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset] = p_route_info;
    p_route_info->hw_position[0] = p_lkp_rlt->snake_idx;
    p_route_info->hw_position[1] = p_lkp_rlt->entry_offset;

    CTC_ERROR_RETURN(_sys_nalpm_write_sram(lchip, p_tcam_item, p_route_info, p_lkp_rlt->snake_idx, p_lkp_rlt->entry_offset, 0, NULL, NULL));

    CTC_BIT_SET(NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[p_lkp_rlt->snake_idx], p_lkp_rlt->entry_offset);

    g_sys_nalpm_master[lchip]->vrf_route_cnt[p_route_info->ip_ver][p_route_info->vrf_id]++;

    ret = _sys_tsingma_nalpm_add_route_cover(lchip, p_tcam_item, p_route_info, nh_id, p_lkp_rlt->total_skip_len, 0, NULL);
    if(ret < 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        return ret;
    }

    return ret;

}

int32
_sys_tsingma_nalpm_renew_dsipda(uint8 lchip, void* dsipda, sys_nh_info_dsnh_t nhinfo)
{
    if (!GetDsIpDa(V, nextHopPtrValid_f, dsipda))
    {
        if (nhinfo.ecmp_valid)
        {
            return CTC_E_NONE;
        }
        SetDsIpDa(V, dsFwdPtrOrEcmpGroupId_f, dsipda, nhinfo.dsfwd_offset);
    }
    else
    {
        SetDsIpDa(V, adNextHopPtr_f, dsipda, nhinfo.dsnh_offset);
    }
    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_move_route(uint8 lchip, uint8 new_lchip, uint8 old_lchip, sys_nalpm_route_info_t* p_route_info)
{
    sys_ipuc_param_t temp_sys_param;
    sal_memset(&temp_sys_param, 0, sizeof(sys_ipuc_param_t));
    temp_sys_param.param.ip_ver = p_route_info->ip_ver;
    temp_sys_param.param.masklen = p_route_info->route_masklen;
    temp_sys_param.param.vrf_id = p_route_info->vrf_id;
    if (p_route_info->ip_ver)
    {
        sal_memcpy(temp_sys_param.param.ip.ipv6, p_route_info->ip, IP_ADDR_SIZE(CTC_IP_VER_6));
    }
    else
    {
        temp_sys_param.param.ip.ipv4 = *(p_route_info->ip);
    }
    if (((32 == temp_sys_param.param.masklen && 0 == temp_sys_param.param.ip_ver) ||
        (128 == temp_sys_param.param.masklen))
        && 1 == p_usw_ipuc_master[lchip]->host_lpm_mode )
    {
         CTC_SET_FLAG(temp_sys_param.param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
    }
    if (p_route_info->ip_ver)
    {
        SYS_IPV6_ADDRESS_SORT(temp_sys_param.param.ip.ipv6);
    }
    _sys_usw_ipuc_db_lookup(lchip, &temp_sys_param);
    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_find_best_position(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, uint8 masklen, uint8* snake_idx, uint8* offset)
{
    uint8 i = 0, j = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;

    *snake_idx = 0xff;
    *offset = 0xff;

    SYS_NALPM_BUCKET_TRANVAS(lchip, i, p_tcam_item->sram_type, p_tcam_item->sram_idx, route_per_snake, snake_entry_cnt)
    {
        if (NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[i]
            == _sys_nalpm_get_snake_bitwdith(lchip, p_tcam_item->sram_type, i))
        {
            continue;
        }

        for (j = 0; j < snake_entry_cnt; j++)
        {
            if (!CTC_IS_BIT_SET(NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[i], j))
            {
                *snake_idx = i;
                *offset = j;
                return CTC_E_NONE;
            }
        }
    }

    return (*snake_idx == 0xff) ? CTC_E_NO_RESOURCE : CTC_E_NONE;
}


int32
_sys_tsingma_nalpm_add_split(uint8 lchip, sys_nalpm_tcam_item_t* p_tcam_item, sys_ipuc_param_t* p_sys_ipuc_param)
{
    int32 ret = CTC_E_NONE;
    uint32 max_split_len = 0;
    trie_t *prefix_trie = NULL;
    uint32 split_pfx[4];
    uint32 pfx_len = 0;
    trie_node_t* split_trie_root = NULL;
    sys_nalpm_route_info_t*  p_pfx_info= NULL;
    sys_nalpm_route_info_t* p_best_route = NULL;
    sys_nalpm_tcam_item_t* p_new_tcam_item = NULL;
    sys_nalpm_prefix_trie_payload_t* p_prefix_payload = NULL;
    sys_nalpm_prefix_trie_payload_t * p_root_payload = NULL;
    uint32 ad_idx = INVALID_DRV_NEXTHOP_OFFSET;
    uint16 sram_idx = 0;
    uint8 sub_bkt = 0;
    uint8  ip_ver = 0;
    uint16 vrf_id = 0;
    uint8 route_in_new_trie = 0;
    sys_nalpm_route_info_t* p_new_route = NULL;
    trie_t *clone_trie = NULL;
    sys_nalpm_prefix_trie_payload_t* p_old_prefix_payload = NULL;
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    uint8 max_split_cnt = SYS_NALPM_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4;

    sys_nalpm_cookie_t* p_cookie = NULL;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1, 1);
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;

     if (1 == p_tcam_item->trie->trie->count)
     {
         SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "The node count of splited trie is one!\n");
         SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
         return CTC_E_NO_RESOURCE;
     }

    /*merge*/
    if (NALPM_TRIE_MEGER_EN(lchip, ip_ver) &&
        sys_tsingma_ipuc_tcam_get_merge_en(lchip, ip_ver, p_ipuc_param->masklen))
    {
        sys_tsingma_nalpm_merge_prefix(lchip,  vrf_id,  p_tcam_item->sram_idx);
    }


    ret = (_sys_tsingma_nalpm_sram_idx_alloc(lchip, ip_ver, &sram_idx, &sub_bkt, 0));

    if (ret != CTC_E_NONE)
    {
        if (NALPM_TRIE_MEGER_EN(lchip, ip_ver))
        {
            sys_tsingma_nalpm_merge_prefix(lchip,  vrf_id,  p_tcam_item->sram_idx);
            ret = (_sys_tsingma_nalpm_sram_idx_alloc(lchip, ip_ver, &sram_idx, &sub_bkt, 0));
        }
        if (ret)
        {
            return ret;
        }
    }
    max_split_cnt = (NALPM_BUCKET_MGR_EN(lchip, ip_ver))? ((NALPM_BUCKET_MAX_ENTRY(lchip) - NALPM_BUCKET_USE_CNT(lchip, sram_idx))): NALPM_BUCKET_MAX_ENTRY(lchip);

    /*backup trie*/
    CTC_ERROR_GOTO(sys_nalpm_trie_clone(p_tcam_item->trie, &clone_trie), ret, error1);

    max_split_len = ((ip_ver == CTC_IP_VER_4)? SYS_NALPM_V4_MASK_LEN_MAX : SYS_NALPM_V6_MASK_LEN_MAX);

    CTC_ERROR_GOTO(sys_nalpm_trie_split (p_tcam_item->trie, max_split_len, FALSE, split_pfx, &pfx_len, &split_trie_root, NULL, FALSE, max_split_cnt),ret,error2);
    p_pfx_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_pfx_info)
    {
        ret =  CTC_E_NO_MEMORY;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        goto error2;
    }
    sal_memset(p_pfx_info, 0, ROUTE_INFO_SIZE(ip_ver));

    if (ip_ver == CTC_IP_VER_4)
    {
        p_pfx_info->ip[0] = split_pfx[0];
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)    split_pfx [%x], pfx_len[%u]\n", __LINE__, split_pfx[0], pfx_len);
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)    split_pfx [%x][%x][%x][%x], pfx_len[%u]\n",
                        __LINE__, split_pfx[0], split_pfx[1], split_pfx[2], split_pfx[3], pfx_len);
        p_pfx_info->ip[0] = split_pfx[0];
        p_pfx_info->ip[1] = split_pfx[1];
        p_pfx_info->ip[2] = split_pfx[2];
        p_pfx_info->ip[3] = split_pfx[3];
    }
    p_pfx_info->tcam_masklen = pfx_len;
    p_pfx_info->ip_ver = ip_ver;
    p_pfx_info->vrf_id = vrf_id;

    p_prefix_payload = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_prefix_trie_payload_t));
    if(NULL == p_prefix_payload)
    {
        ret =  CTC_E_NO_MEMORY;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        goto error2;
    }
    sal_memset(p_prefix_payload, 0, sizeof(sys_nalpm_prefix_trie_payload_t));
    p_new_tcam_item = &p_prefix_payload->tcam_item;
    p_new_tcam_item->p_prefix_info = p_pfx_info;

    ret = _sys_tsingma_nalpm_tcam_idx_alloc(lchip, p_ipuc_param, p_new_tcam_item);
    if (CTC_E_NONE != ret)
    {
        goto error3;
    }

    p_new_tcam_item->sram_idx = sram_idx;
    p_new_tcam_item->sub_bkt = sub_bkt;

    CTC_ERROR_GOTO(sys_nalpm_trie_init (max_split_len, &(p_new_tcam_item->trie)),ret, error5);
    p_new_tcam_item->trie->trie = split_trie_root;

    if (p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_128)
    {
        p_new_tcam_item->sram_type = (p_new_tcam_item->p_prefix_info->tcam_masklen > 64 && g_sys_nalpm_master[lchip]->v6_mode)?
                                 SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT: SYS_NALPM_SRAM_TYPE_V6_128;
    }
    else
    {
        p_new_tcam_item->sram_type = p_tcam_item->sram_type;
    }

    /*add new tcam pfx to prefix trie*/
    prefix_trie = g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id];
    CTC_ERROR_GOTO(sys_nalpm_trie_insert (prefix_trie, split_pfx, NULL, pfx_len, (trie_node_t *) p_prefix_payload, 0),ret, error6);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)    p_prefix_payload [%p]\n",__LINE__,p_prefix_payload);


    /*prepare cookie data*/
    _sys_tsingma_nalpm_create_cookie(lchip, p_tcam_item, p_new_tcam_item, &p_cookie);

    /*alloc split offset*/
    _sys_tsingma_nalpm_alloc_offset_array(lchip, p_new_tcam_item, p_cookie);

    /*travase new tree*/
    CTC_ERROR_GOTO(_sys_tsingma_nalpm_renew_route_trie(lchip, p_new_tcam_item, p_cookie, 1),ret , error6);

    /*travase old tree*/
    CTC_ERROR_GOTO(_sys_tsingma_nalpm_renew_route_trie(lchip, p_tcam_item, p_cookie, 0), ret, error6);

    route_in_new_trie = p_cookie->route_in_new_trie;
    p_new_route = p_cookie->p_new_route;

    _sys_tsingma_nalpm_reinstall_element(lchip, p_tcam_item, p_cookie);


    if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
    {
        /*update old bucket*/
        CTC_ERROR_GOTO(_sys_tsingma_nalpm_bucket_list_update(lchip, p_tcam_item->sram_idx, -split_trie_root->count + 1), ret, error6);

        /*update new bucket*/
        CTC_ERROR_GOTO(_sys_tsingma_nalpm_bucket_list_update(lchip, p_new_tcam_item->sram_idx, split_trie_root->count), ret, error6);

    }
    p_old_prefix_payload = CONTAINER_OF(p_tcam_item, sys_nalpm_prefix_trie_payload_t, tcam_item);
    CTC_ERROR_GOTO(_sys_tsingma_nalpm_search_best_route_in_sram(lchip, &(p_old_prefix_payload->node), p_new_tcam_item->p_prefix_info, &p_best_route), ret, error6);
    if (p_best_route)
    {
        p_new_tcam_item->p_prefix_info->ad_idx = p_best_route->ad_idx;
    }
    else
    {
        p_root_payload = CONTAINER_OF(prefix_trie->trie, sys_nalpm_prefix_trie_payload_t, node);
        CTC_ERROR_GOTO(_sys_tsingma_nalpm_read_tcam(lchip, &p_root_payload->tcam_item, &ad_idx), ret, error6);
        p_new_tcam_item->p_prefix_info->ad_idx = ad_idx;
    }
    p_new_tcam_item->p_AD_route = p_best_route;

    /*install to hw*/
    _sys_tsingma_nalpm_write_route_cookie(lchip, NULL, p_new_tcam_item, p_cookie);

    CTC_ERROR_GOTO(_sys_tsingma_nalpm_write_tcam(lchip, p_new_tcam_item, DO_ADD, 0),ret, error6);

    if(DRV_FROM_TMM(lchip) && g_sys_nalpm_master[lchip]->move_hit_en)
    {
        _sys_tmm_nalpm_move_hit(lchip, p_tcam_item, p_new_tcam_item, p_cookie);
    }

    _sys_tsingma_nalpm_write_route_cookie(lchip, p_tcam_item, NULL, p_cookie);

    mem_free(p_cookie);

    if (route_in_new_trie)
    {
        trie_node_t *node;
        CTC_ERROR_RETURN(sys_nalpm_trie_find_lpm (prefix_trie, split_pfx,  pfx_len , &node, 0));
        _sys_tsingma_nalpm_add_route_cover(lchip, p_new_tcam_item, p_new_route, p_sys_ipuc_param->param.nh_id, node->total_skip_len, 0, NULL);
         p_sys_ipuc_param->info->tcam_idx = p_new_tcam_item->tcam_idx;
    }
    else
    {
        sys_nalpm_prefix_trie_payload_t* pfx_pld = NULL;
        pfx_pld = CONTAINER_OF(p_tcam_item, sys_nalpm_prefix_trie_payload_t, tcam_item);
        _sys_tsingma_nalpm_add_route_cover(lchip, p_tcam_item, p_new_route, p_sys_ipuc_param->param.nh_id, pfx_pld->node.total_skip_len, 0, NULL);
          p_sys_ipuc_param->info->tcam_idx = p_tcam_item->tcam_idx;
    }


    g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]++;
    sys_nalpm_trie_clear(clone_trie->trie);
    sys_nalpm_trie_destroy(clone_trie);

    return ret;


error6:
    if (p_cookie)
    {
        mem_free(p_cookie);
    }

    sys_nalpm_trie_destroy((p_new_tcam_item->trie));
error5:
    _sys_tsingma_nalpm_tcam_idx_free(lchip, p_ipuc_param, p_new_tcam_item);
error3:
    if (p_prefix_payload)
    {
        mem_free(p_prefix_payload);
    }
error2:
    sys_nalpm_trie_clear(p_tcam_item->trie->trie);
    sys_nalpm_trie_clear(split_trie_root);
    sys_nalpm_trie_destroy(p_tcam_item->trie);
    p_tcam_item->trie = clone_trie;
    if(p_pfx_info)
        mem_free(p_pfx_info);
error1:
    _sys_tsingma_nalpm_sram_idx_free(lchip, sram_idx, ip_ver);

    return ret;
}

int32
sys_tsingma_nalpm_auto_merge(uint8 lchip, uint8 enable)
{
    LCHIP_CHECK(lchip);
    SYS_NALPM_INIT_CHECK;
    g_sys_nalpm_master[lchip]->frag_arrange_enable = enable;
    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_set_fragment_status(uint8 lchip, uint8 ip_ver, uint8 status)
{
    LCHIP_CHECK(lchip);
    SYS_NALPM_INIT_CHECK;
    g_sys_nalpm_master[lchip]->frag_arrange_status[ip_ver] = status;
    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_get_fragment_status(uint8 lchip, uint8 ip_ver, uint8* status)
{
    LCHIP_CHECK(lchip);
    SYS_NALPM_INIT_CHECK;
    *status = g_sys_nalpm_master[lchip]->frag_arrange_status[ip_ver];
    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_get_fragment_auto_enable(uint8 lchip, uint8* enable)
{
    LCHIP_CHECK(lchip);
    SYS_NALPM_INIT_CHECK;
    *enable = g_sys_nalpm_master[lchip]->frag_arrange_enable;
    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_hash_free_node_data(void* node_data, void* user_data)
{
    mem_free(node_data);
    return CTC_E_NONE;
}

int32
_sys_tsingma_ipuc_hash_make(sys_nalpm_route_info_t* p_route_info)
{
    sys_nalpm_route_key_t key;
    sal_memset(key.ip.ipv6, 0, sizeof(ipv6_addr_t));
    key.ip_ver = p_route_info->ip_ver;
    key.vrfid = p_route_info->vrf_id;
    key.masklen = p_route_info->route_masklen;
    if (key.ip_ver == CTC_IP_VER_6)
    {
        sal_memcpy(key.ip.ipv6, p_route_info->ip , sizeof(ipv6_addr_t));
    }
    else
    {
       key.ip.ipv4 = p_route_info->ip[0];
    }

    return ctc_hash_caculate(sizeof(sys_nalpm_route_key_t), &key);
}

int32
_sys_tsingma_ipuc_hash_cmp(sys_nalpm_route_info_t* p_db_route_info, sys_nalpm_route_info_t* p_route_info)
{
    if (p_db_route_info->ip_ver != p_route_info->ip_ver)
    {
        return FALSE;
    }
    if (p_db_route_info->vrf_id != p_route_info->vrf_id)
    {
        return FALSE;
    }
    if (p_db_route_info->route_masklen != p_route_info->route_masklen)
    {
        return FALSE;
    }
    if (p_db_route_info->ip_ver)
    {
        if (sal_memcmp(p_db_route_info->ip, p_route_info->ip, sizeof(ipv6_addr_t)))
        {
            return FALSE;
        }
    }
    else
    {
        if (p_db_route_info->ip[0] != p_route_info->ip[0])
        {
            return FALSE;
        }
    }
    return TRUE;
}

int32
_sys_tsingma_tcam_hash_make(sys_nalpm_tcam_item_t* p_tcam_item)
{
    uint16 tcam_idx = p_tcam_item->tcam_idx;
    return ctc_hash_caculate(sizeof(uint16), &tcam_idx);
}

int32
_sys_tsingma_tcam_hash_cmp(sys_nalpm_tcam_item_t* p_db_tcam_item, sys_nalpm_tcam_item_t* p_tcam_item)
{
    if (p_db_tcam_item->tcam_idx == p_tcam_item->tcam_idx)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

typedef enum _alpm_cb_merge_type_e {
    ACB_MERGE_INVALID = 0,
    ACB_MERGE_CHILD_TO_PARENT,
    ACB_MERGE_PARENT_TO_CHILD,
    ACB_MERGE_LCHILD_TO_RCHILD
} _alpm_cb_merge_type_t;

#define ACB_REPART_THRESHOLD 8
#define ACB_MERGE_THRESHOLD  8

typedef sys_nalpm_prefix_trie_payload_t sys_alpm_pvt_node_t;

#define ALPM_PVT_TRIE(lchip, vrf_id, ip_ver) g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id]
#define PVT_BKT_TRIE(pvt_node)          ((pvt_node)->tcam_item.trie)


int32
sys_tsingma_nalpm_get_snake_sram_used(uint8 lchip,
                         uint8 ip_ver,
                         uint32 vrf_id,
                         sys_alpm_pvt_node_t *pvt_node)
{
    uint32 used_cnt = 0;
    uint8 i = 0, j =0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    sys_nalpm_tcam_item_t* p_tcam_item = NULL;

    p_tcam_item = &pvt_node->tcam_item;


    SYS_NALPM_BUCKET_LOOP(lchip, i, p_tcam_item->sram_type, p_tcam_item->sram_idx, route_per_snake, snake_entry_cnt)
    {
        for (j = 0; j < snake_entry_cnt; j++)
        {
            if (CTC_IS_BIT_SET(NALPM_BUCKET(lchip, p_tcam_item->sram_idx).bitmap[i], j))
            {
                used_cnt++;
            }
        }
    }

    return used_cnt;
}

STATIC int32
_sys_tsingma_remove_pvt_resource(uint8 lchip, sys_alpm_pvt_node_t *pvt_node)
{
    ctc_ipuc_param_t ipuc_param;
    int32 ret = 0;
    sal_memset(&ipuc_param, 0, sizeof(ipuc_param));
    ipuc_param.ip_ver = pvt_node->tcam_item.p_prefix_info->ip_ver;

    CTC_ERROR_RETURN(_sys_tsingma_nalpm_write_tcam(lchip, &pvt_node->tcam_item, DO_DEL, 0));
    CTC_ERROR_RETURN(_sys_tsingma_nalpm_tcam_idx_free(lchip, &ipuc_param, &pvt_node->tcam_item));
    CTC_ERROR_RETURN(_sys_tsingma_nalpm_sram_idx_free(lchip, pvt_node->tcam_item.sram_idx, ipuc_param.ip_ver));

    return ret;
}

STATIC int32
_sys_tsingma_nalpm_merge_pvt(uint8 lchip,
                  sys_alpm_pvt_node_t *src_pvt,
                  sys_alpm_pvt_node_t *dst_pvt,
                  uint32 merge_dir)
{
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = 0;
    uint32 vrf_id = 0;
    uint32 key_len = 0;
    uint8 merge_cnt = 0;
    trie_node_t *tn = NULL;
    sys_alpm_pvt_node_t *prt_pvt = NULL;
    sys_alpm_pvt_node_t *chd_pvt = NULL;

    trie_t *clone_prt_trie = NULL;
    trie_t *clone_chd_trie = NULL;
    sys_nalpm_route_info_t*  new_pivot_pfx_info = NULL;
    sys_nalpm_prefix_trie_payload_t* new_pivot = NULL;


    uint32 key[4] = {0};

    if (merge_dir == ACB_MERGE_PARENT_TO_CHILD)
    {
        prt_pvt = src_pvt;
        chd_pvt = dst_pvt;
    }
    else
    {
        prt_pvt = dst_pvt;
        chd_pvt = src_pvt;
    }

    /* 3. Merge trie */
    ip_ver = chd_pvt->tcam_item.p_prefix_info->ip_ver;
    vrf_id = chd_pvt->tcam_item.p_prefix_info->vrf_id;


    merge_cnt = PVT_BKT_TRIE(chd_pvt)->trie->count;

    CTC_ERROR_RETURN(sys_nalpm_trie_clone(PVT_BKT_TRIE(prt_pvt), &clone_prt_trie));
    CTC_ERROR_RETURN(sys_nalpm_trie_clone(PVT_BKT_TRIE(chd_pvt), &clone_chd_trie));

    sal_memset(key, 0 , sizeof(key));
    sal_memcpy(key, chd_pvt->tcam_item.p_prefix_info->ip, IP_ADDR_SIZE(ip_ver));
    key_len = chd_pvt->tcam_item.p_prefix_info->tcam_masklen;

    CTC_ERROR_GOTO(trie_merge(PVT_BKT_TRIE(prt_pvt), PVT_BKT_TRIE(chd_pvt)->trie,  key, key_len), ret, error1);

    if (merge_dir == ACB_MERGE_LCHILD_TO_RCHILD)
    {
        uint32 pfx[4] = {0};
        uint32 prefix_len = 0;
        uint32 key1[4] = {0};
        uint32 key_len1 = 0;
        ctc_ipuc_param_t ipuc_param;
        uint16 route_info_size = 0;

        sys_trie_find_lpm_prefix(PVT_BKT_TRIE(prt_pvt), pfx, &prefix_len);

        /*����lpm parent ǰ׺��Ϣ������tcam*/
        sal_memset(&ipuc_param, 0, sizeof(ipuc_param));
        ipuc_param.ip_ver = prt_pvt->tcam_item.p_prefix_info->ip_ver;

        route_info_size = ROUTE_INFO_SIZE(ip_ver);

        new_pivot_pfx_info = mem_malloc(MEM_IPUC_MODULE, route_info_size);
        if (NULL == new_pivot_pfx_info)
        {
            ret =  CTC_E_NO_MEMORY;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
            goto error1;
        }

        sal_memset(new_pivot_pfx_info, 0, route_info_size);

        new_pivot = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_prefix_trie_payload_t));
        if (NULL == new_pivot)
        {
            ret =  CTC_E_NO_MEMORY;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
            goto error2;
        }
        sal_memset(new_pivot, 0, sizeof(sys_nalpm_prefix_trie_payload_t));
        sal_memcpy(&new_pivot->tcam_item , &prt_pvt->tcam_item, sizeof(sys_nalpm_tcam_item_t));
        sal_memcpy(new_pivot_pfx_info, prt_pvt->tcam_item.p_prefix_info, route_info_size);
        new_pivot->tcam_item.p_prefix_info = new_pivot_pfx_info;

        new_pivot->tcam_item.p_prefix_info->tcam_masklen = prefix_len;
        sal_memcpy(new_pivot->tcam_item.p_prefix_info->ip, pfx, sizeof(pfx));


        ret = _sys_tsingma_nalpm_tcam_idx_alloc(lchip, &ipuc_param, &(new_pivot->tcam_item));
        if (CTC_E_NONE != ret)
        {
            goto error3;
        }

        ret = sys_nalpm_trie_insert(ALPM_PVT_TRIE(lchip, vrf_id, ip_ver), pfx, NULL, prefix_len, (trie_node_t *) new_pivot, 0);
        if (CTC_E_NONE != ret)
        {
            goto error3;
        }

        /*update new snake sram entry*/
        _sys_tsingma_nalpm_merge_route_trie(lchip, merge_cnt, &new_pivot->tcam_item, &chd_pvt->tcam_item);

        if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
        {
            /*update chd_pvt bucket*/
            _sys_tsingma_nalpm_bucket_list_update(lchip, chd_pvt->tcam_item.sram_idx, -merge_cnt);

            /*update prt_pvt bucket*/
            _sys_tsingma_nalpm_bucket_list_update(lchip, new_pivot->tcam_item.sram_idx, merge_cnt);

        }

        _sys_tsingma_nalpm_write_route_trie(lchip, &new_pivot->tcam_item, 0);
         _sys_tsingma_nalpm_write_tcam(lchip, &(new_pivot->tcam_item), DO_ADD, 0);

        _sys_tsingma_nalpm_write_tcam(lchip, &prt_pvt->tcam_item, DO_DEL, 0);
        _sys_tsingma_nalpm_tcam_idx_free(lchip, &ipuc_param, &prt_pvt->tcam_item);
        /* delete child pvt from trie */
        trie_delete(ALPM_PVT_TRIE(lchip, vrf_id, ip_ver), key, key_len, &tn);

        /* delete parent pvt from trie */
        sal_memcpy(key1, prt_pvt->tcam_item.p_prefix_info->ip, IP_ADDR_SIZE(ip_ver));
        key_len1 = prt_pvt->tcam_item.p_prefix_info->tcam_masklen;
        trie_delete(ALPM_PVT_TRIE(lchip, vrf_id, ip_ver), key1, key_len1, &tn);
        mem_free(prt_pvt->tcam_item.p_prefix_info);
        mem_free(prt_pvt);

    }
    else
    {
        /*update new snake sram entry*/
        _sys_tsingma_nalpm_merge_route_trie(lchip, merge_cnt, &prt_pvt->tcam_item, &chd_pvt->tcam_item);

        merge_cnt = PVT_BKT_TRIE(chd_pvt)->trie->count;

        if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
        {
            /*update chd_pvt bucket*/
            _sys_tsingma_nalpm_bucket_list_update(lchip, chd_pvt->tcam_item.sram_idx, -merge_cnt);

            /*update prt_pvt bucket*/
            _sys_tsingma_nalpm_bucket_list_update(lchip, prt_pvt->tcam_item.sram_idx, merge_cnt);

        }

        _sys_tsingma_nalpm_write_route_trie(lchip, &prt_pvt->tcam_item, 0);

       /* Destroy child pvt from trie, tn is chd_pvt */
        trie_delete(ALPM_PVT_TRIE(lchip, vrf_id, ip_ver), key, key_len, &tn);
    }

    _sys_tsingma_nalpm_write_tcam(lchip, &chd_pvt->tcam_item, DO_DEL, 0);

    /* 6.remove prefix  resource*/
    _sys_tsingma_remove_pvt_resource(lchip, chd_pvt);

    /*remove source trie*/
    sys_nalpm_trie_destroy(PVT_BKT_TRIE(chd_pvt));
    mem_free(chd_pvt->tcam_item.p_prefix_info);
    mem_free(chd_pvt);

    if (clone_prt_trie)
    {
        sys_nalpm_trie_clear(clone_prt_trie->trie);
        sys_nalpm_trie_destroy(clone_prt_trie);
    }
    if (clone_chd_trie)
    {
        sys_nalpm_trie_clear(clone_chd_trie->trie);
        sys_nalpm_trie_destroy(clone_chd_trie);
    }

    return ret;


error3:
    mem_free(new_pivot);

error2:
    mem_free(new_pivot_pfx_info);

error1:

    sys_nalpm_trie_clear(prt_pvt->tcam_item.trie->trie);
    sys_nalpm_trie_destroy(prt_pvt->tcam_item.trie);
    sys_nalpm_trie_destroy(chd_pvt->tcam_item.trie);
    prt_pvt->tcam_item.trie = clone_prt_trie;
    chd_pvt->tcam_item.trie = clone_chd_trie;
    return ret;
}


STATIC int32
sys_tsingma_nalpm_merge_cb(trie_node_t *ptrie, trie_node_t *trie,
                 trie_traverse_states_e_t *state, void *info)
{
    int32 rv = 0;
    uint32 lchip = 0;
    uint32 prt_cnt = 0;
    uint32 chd_cnt = 0;
    uint32 vrf_id = 0;
    uint8 ip_ver = 0;

    sys_alpm_pvt_node_t *prt_pvt, *chd_pvt, *src_pvt, *dst_pvt;
    sys_alpm_cb_merge_ctrl_t *merge_ctrl;
    _alpm_cb_merge_type_t merge_dir = ACB_MERGE_INVALID;

    prt_pvt = (sys_alpm_pvt_node_t *)ptrie;
    chd_pvt = (sys_alpm_pvt_node_t *)trie;
    if (!prt_pvt)
    {
        return CTC_E_NONE;
    }

    merge_ctrl = (sys_alpm_cb_merge_ctrl_t *)info;
    lchip   = merge_ctrl->lchip;
    ip_ver = merge_ctrl->ip_ver;
    vrf_id = merge_ctrl->vrf_id;

    if (PVT_BKT_TRIE(prt_pvt)->trie == NULL)
    {
        merge_dir = ACB_MERGE_PARENT_TO_CHILD;
    }

    if (PVT_BKT_TRIE(chd_pvt)->trie == NULL)
    {
        merge_dir = ACB_MERGE_CHILD_TO_PARENT;
    }

    if (merge_dir == ACB_MERGE_INVALID)
    {
        uint32 prt_entrys = 0;
        uint32 chd_entrys = 0;

        prt_cnt = _sys_tsingma_nalpm_get_bucket_entry_cnt(lchip, prt_pvt->tcam_item.sram_type);
        chd_cnt = _sys_tsingma_nalpm_get_bucket_entry_cnt(lchip, chd_pvt->tcam_item.sram_type);

        prt_entrys = prt_cnt - sys_tsingma_nalpm_get_snake_sram_used(lchip, ip_ver, vrf_id, prt_pvt); /*����� �յ�bank����*/
        chd_entrys = chd_cnt - sys_tsingma_nalpm_get_snake_sram_used(lchip, ip_ver, vrf_id, chd_pvt);/*�ӽ�� �յ�bank����*/


        if (PVT_BKT_TRIE(chd_pvt)->trie->count <= prt_entrys)
        {
            merge_dir   = ACB_MERGE_CHILD_TO_PARENT;
        }
        else if (PVT_BKT_TRIE(prt_pvt)->trie->count <= chd_entrys)
        {
            merge_dir   = ACB_MERGE_PARENT_TO_CHILD;
        }
        else
        {
            return CTC_E_NONE;
        }

    }

    if (merge_dir == ACB_MERGE_PARENT_TO_CHILD)
    {
        src_pvt = prt_pvt;
        dst_pvt = chd_pvt;
    }
    else
    {
        src_pvt = chd_pvt;
        dst_pvt = prt_pvt;
    }

    rv = _sys_tsingma_nalpm_merge_pvt(lchip, src_pvt, dst_pvt, merge_dir);

    if (rv < 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "alpm merge failed rv %d\n", rv);
        return rv;
    }

    *state = TRIE_TRAVERSE_STATE_DELETED;

    ++merge_ctrl->merge_count;

    return CTC_E_NONE;

}


int32
sys_tsingma_nalpm_merge_lr_cb(trie_node_t *ptrie, trie_node_t * trie, trie_traverse_states_e_t *state, void *info)
{
    int32 ret = 0;
    uint32 lchip = 0;
    uint8 i = 0;
    trie_node_t* son[2] = {NULL};
    sys_alpm_cb_merge_ctrl_t *merge_ctrl;
    sys_nalpm_prefix_trie_payload_t*  leaf0;
    sys_nalpm_prefix_trie_payload_t*  leaf1;
    uint8 capacity = 0;
    uint32 no_sram_idx = 0;
    son[0] = trie->child[0].child_node;
    son[1] = trie->child[1].child_node;

    if(NULL == son[0] || NULL == son[1])
    {
        return CTC_E_NONE;
    }

    if(trie->type == INTERNAL && son[0]->type == INTERNAL && son[1]->type == INTERNAL
        && son[0]->count == 2 && son[1]->count == 2
        && son[0]->child[0].child_node && son[0]->child[1].child_node
        && son[1]->child[0].child_node && son[1]->child[1].child_node
        && son[0]->child[0].child_node->type == PAYLOAD && son[0]->child[1].child_node->type == PAYLOAD
        && son[1]->child[0].child_node->type == PAYLOAD && son[1]->child[1].child_node->type == PAYLOAD)
    {
        merge_ctrl = (sys_alpm_cb_merge_ctrl_t *)info;
        lchip  = merge_ctrl->lchip;
         no_sram_idx = merge_ctrl->sram_idx;

        for(i = 0; i < 2; i++)
        {
            leaf0 = (sys_nalpm_prefix_trie_payload_t*)son[i]->child[0].child_node;
            leaf1 = (sys_nalpm_prefix_trie_payload_t*)son[i]->child[1].child_node;

            capacity = _sys_tsingma_nalpm_get_bucket_entry_cnt(lchip, leaf0->tcam_item.sram_type);

            if (leaf0->node.skip_len != 0 || leaf1->node.skip_len != 0 )
            {
                continue;
            }

            if (leaf0->tcam_item.p_prefix_info->tcam_masklen != leaf1->tcam_item.p_prefix_info->tcam_masklen)
            {
                continue;
            }

            if (leaf0->tcam_item.trie->trie->count + leaf1->tcam_item.trie->trie->count > capacity)
            {
                continue;
            }

            if (leaf1->tcam_item.sram_idx == no_sram_idx || leaf0->tcam_item.sram_idx == no_sram_idx)
            {
                continue;
            }

            ret = _sys_tsingma_nalpm_merge_pvt(lchip, leaf1, leaf0, ACB_MERGE_LCHILD_TO_RCHILD);

            if (ret != CTC_E_NONE)
            {
                return ret;
            }
            else
            {
                ++merge_ctrl->merge_count;
            }

            *state = TRIE_TRAVERSE_STATE_DONE;

        }

    }
    return CTC_E_NONE;
}


int32
sys_tsingma_nalpm_merge_prefix(uint8 lchip, uint32 vrf_id, uint32 sram_idx)
{
    int32 rv = CTC_E_NONE;

    sys_alpm_cb_merge_ctrl_t merge_ctrl;
    trie_traverse_states_e_t state = TRIE_TRAVERSE_STATE_NONE;

    LCHIP_CHECK(lchip);
    SYS_NALPM_INIT_CHECK;
    if( g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6][vrf_id]&&
       g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6][vrf_id]->trie)
    {
        sal_memset(&merge_ctrl, 0, sizeof(merge_ctrl));
        merge_ctrl.lchip     = lchip;
        merge_ctrl.vrf_id   = vrf_id;
        merge_ctrl.ip_ver   = CTC_IP_VER_6;
        merge_ctrl.sram_idx = sram_idx;

        rv=  sys_nalpm_trie_traverse_lr(g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6][vrf_id]->trie, &state,
                                        sys_tsingma_nalpm_merge_lr_cb, &merge_ctrl);

        if (rv < 0)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "sys_nalpm_auto_merge failed, vrf_id %d rv %d.\n", vrf_id, rv);
        }

        g_sys_nalpm_master[lchip]->merge_cnt += merge_ctrl.merge_count;
    }
    return rv;
}

/* sys_tsingma_nalpm_merge() will be use at ipuc_add_api, can not lock */
int32
sys_tsingma_nalpm_merge(uint8 lchip, uint32 vrf_id, uint8 ip_ver)
{
    int32 rv = CTC_E_NONE;
    trie_t *pvt_trie;
    sys_alpm_cb_merge_ctrl_t merge_ctrl;

    LCHIP_CHECK(lchip);
    SYS_NALPM_INIT_CHECK;
    CTC_IP_VER_CHECK(ip_ver);
    SYS_IP_VRFID_CHECK(vrf_id);

    pvt_trie = ALPM_PVT_TRIE(lchip, vrf_id, ip_ver);

    if (pvt_trie == NULL ||
    pvt_trie->trie == NULL || MERGE_NO_RESOURCE == g_sys_nalpm_master[lchip]->frag_arrange_status[ip_ver])
    {
        return CTC_E_NONE;
    }

    sal_memset(&merge_ctrl, 0, sizeof(merge_ctrl));
    merge_ctrl.lchip     = lchip;
    merge_ctrl.vrf_id   = vrf_id;
    merge_ctrl.ip_ver   = ip_ver;


    rv = sys_nalpm_trie_traverse2(pvt_trie, sys_tsingma_nalpm_merge_cb, &merge_ctrl,  _TRIE_POSTORDER_TRAVERSE);
    if (rv < 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Logic bucket merge failed, ip_ver %d vrf_id %d rv %d.\n", ip_ver, vrf_id, rv);
    }

    if (merge_ctrl.merge_count == 0)
    {
        rv = CTC_E_NO_RESOURCE;
    }

    return rv;
}

int32
sys_tsingma_nalpm_merge_by_param(uint8 lchip, uint32 vrf_id, uint8 ip_ver)
{
    int32 ret = CTC_E_NONE;

    SYS_NALPM_INIT_CHECK;

    LCHIP_CHECK(lchip);
    CTC_IP_VER_CHECK(ip_ver);
    SYS_IP_VRFID_CHECK(vrf_id);

    SYS_IPUC_LOCK;

    ret = sys_tsingma_nalpm_merge(lchip, vrf_id, ip_ver);

    SYS_IPUC_UNLOCK;
    return ret;
}

int32
sys_tmm_nalpm_ageing_opt(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, uint8 opt, uint8 *p_hit)
{
    sys_nalpm_route_info_t*  p_route_info = NULL;
    sys_nalpm_route_store_info_t lkp_rlt;
    sys_nalpm_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    uint8 ip_ver = 0;
    int32 ret = CTC_E_NONE;
    uint32 hw_idx = 0;
    uint8 domain_type = 0;

    SYS_NALPM_INIT_CHECK;
    LCHIP_CHECK(lchip);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    /* prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    p_route_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_route_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_route_info, 0 , (ROUTE_INFO_SIZE(ip_ver)));
    p_route_info->ip_ver = ip_ver;
    sal_memcpy(p_route_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_route_info->route_masklen = p_ipuc_param->masklen;
    p_route_info->vrf_id = p_ipuc_param->vrf_id;
    SYS_IP_V6_SORT(p_route_info);

    if(p_ipuc_param->masklen== 0)
    {
        goto end;
    }

    /* 1. lookup sw node */
    sal_memset(p_lkp_rlt, 0 , sizeof(sys_nalpm_route_store_info_t));
    CTC_ERROR_GOTO(_sys_tsingma_nalpm_route_lkp(lchip, p_route_info, p_lkp_rlt), ret, end);
    if (!p_lkp_rlt->sram_hit)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- sys_tmm_nalpm_ageing_opt\r\n", __LINE__);
        ret =  CTC_E_NOT_EXIST;
        goto end;
    }
    mem_free(p_route_info);

    p_route_info = p_lkp_rlt->p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset];
    hw_idx = sys_tsingma_nalpm_get_hw_sram_idx(lchip, p_lkp_rlt->p_tcam_item, p_route_info->hw_position[0]);
    domain_type = p_route_info->hw_position[0] >= g_sys_nalpm_master[lchip]->snake_per_group ?
    SYS_AGING_DOMAIN_LPM_HASH_GROUP1 :  SYS_AGING_DOMAIN_LPM_HASH_GROUP0;
    if (opt == IPUC_LPM_AGING_GET)/*get*/
    {
        ret = MCHIP_LA(lchip)->get_aging_status(lchip, domain_type, ((p_route_info->hw_position[1] << 24) | hw_idx), p_hit);
        if (1 == *p_hit)
        {
            goto end0;
        }
    }
    else
    {
        CTC_ERROR_RETURN(MCHIP_LA(lchip)->set_aging_status(lchip, domain_type, ((p_route_info->hw_position[1] << 24) | hw_idx), 0, *p_hit ? 1:0));
    }

    ret = _sys_tsingma_nalpm_add_route_cover(lchip, p_lkp_rlt->p_tcam_item,
                                            p_lkp_rlt->p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset],
                                            0,
                                            p_lkp_rlt->total_skip_len,
                                            opt,
                                            p_hit);
    return ret;
 end:
    mem_free(p_route_info);
 end0:
    return ret;
}

int32
sys_tsingma_nalpm_add(uint8 lchip, void* p_sys_ipuc_param_v, uint32 ad_index, void* data)
{
    sys_nalpm_route_info_t*  p_route_info = NULL;
    sys_nalpm_route_store_info_t lkp_rlt;
    sys_nalpm_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm_trie_payload_t* p_route_payload = NULL;
    sys_ipuc_param_t* p_sys_ipuc_param = (sys_ipuc_param_t*)p_sys_ipuc_param_v;
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    uint8 ip_ver = 0;
    int32 ret = CTC_E_NONE;
    uint32 key[4] = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    if (p_ipuc_param->masklen > 64 &&  p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM] == 0 &&
        p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB] == 0)
    {
        return CTC_E_INVALID_PARAM;
    }

    /* prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    p_route_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_route_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_route_info, 0 , (ROUTE_INFO_SIZE(ip_ver)));
    p_route_info->ip_ver = ip_ver;
    sal_memcpy(p_route_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_route_info->ad_idx = ad_index;
    p_route_info->route_masklen = p_ipuc_param->masklen;
    p_route_info->vrf_id = p_ipuc_param->vrf_id;
    p_route_info->ipuc_info = p_sys_ipuc_param->info;
    SYS_IP_V6_SORT(p_route_info);

    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
    {
        CTC_ERROR_GOTO(_sys_tsingma_nalpm_wb_restore_prefix(lchip, p_sys_ipuc_param, p_route_info), ret, error1);

        if (p_route_info)
        {
            mem_free(p_route_info);
        }
    }
    else
    {
         /* vrf is not inited*/
        if(g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][p_route_info->vrf_id] == 0)
        {
             /* init vrf memory and default route*/
            CTC_ERROR_GOTO(_sys_tsingma_nalpm_route_vrf_init(lchip, p_ipuc_param),ret, error1);
        }

        if(p_ipuc_param->masklen== 0)
        {
            CTC_ERROR_GOTO(sys_tsingma_nalpm_update( lchip, p_sys_ipuc_param, ad_index),ret, error1);
            g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][p_route_info->vrf_id]++;
            mem_free(p_route_info);
            return ret;
        }

        /* 1. lookup sw node */
        sal_memset(p_lkp_rlt, 0 , sizeof(sys_nalpm_route_store_info_t));
        CTC_ERROR_GOTO(_sys_tsingma_nalpm_route_lkp(lchip, p_route_info, p_lkp_rlt), ret, error1);
        if (!p_lkp_rlt->tcam_hit || p_lkp_rlt->p_tcam_item == NULL)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- tcam not hit\r\n", __LINE__);
            ret =  CTC_E_NOT_EXIST;
            goto error1;
        }
        if (p_lkp_rlt->sram_hit)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- sram hit\r\n", __LINE__);
            ret =  CTC_E_EXIST;
            goto error1;
        }
        p_tcam_item = p_lkp_rlt->p_tcam_item;

        /*check and set sram type*/
        if ((p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_64
            || p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_64_EXT) && p_route_info->route_masklen > 64)
        {
            goto error1;
        }

        if (p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_VOID)
        {
            _sys_tsingma_nalpm_set_sram_type(lchip, p_route_info->ip_ver, p_route_info->route_masklen, p_tcam_item);
        }


        /* should not split tree when arrange fragment, this will lead to use more tcam resource */
        if(_sys_tsingma_nalpm_sram_entry_is_full(lchip, p_tcam_item, p_route_info) && (uint8*)data)
        {
            ret = CTC_E_NOT_SUPPORT;
            goto error1;
        }

        p_route_payload = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_trie_payload_t));
        if (NULL == p_route_payload)
        {
            ret = CTC_E_NO_MEMORY;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
            goto error1;
        }
        sal_memset(p_route_payload, 0 , sizeof(sys_nalpm_trie_payload_t));
        p_route_payload->p_route_info = p_route_info;
        sal_memcpy(key, p_route_info->ip, IP_ADDR_SIZE(p_route_info->ip_ver));

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)  p_route_payload=[%p],p_route_info=[%p], ip_ver[%u]\n", __LINE__, p_route_payload, p_route_info, p_route_info->ip_ver);

        ret = sys_nalpm_trie_insert (p_tcam_item->trie, key, NULL, p_route_info->route_masklen, (trie_node_t *) p_route_payload, 1);
        if (CTC_E_NONE != ret)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "!!!trie_insert failed: %d\r\n", ret);
            goto error2;
        }

        if (!_sys_tsingma_nalpm_sram_entry_is_full(lchip, p_tcam_item, p_route_info))
        {

            CTC_ERROR_GOTO(_sys_tsingma_nalpm_add_directly(lchip, p_tcam_item, p_route_info, p_lkp_rlt, p_sys_ipuc_param->param.nh_id), ret, error3);

            if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
            {
                /*update bucket*/
                CTC_ERROR_GOTO(_sys_tsingma_nalpm_bucket_list_update(lchip, p_tcam_item->sram_idx, 1), ret, error3)
            }

             p_sys_ipuc_param->info->tcam_idx = p_tcam_item->tcam_idx;
        }
        else
        {
            p_route_info->hw_position[0] = 0xff;
            p_route_info->hw_position[1] = 0xff;
            CTC_ERROR_GOTO(_sys_tsingma_nalpm_add_split(lchip, p_tcam_item, p_sys_ipuc_param), ret, error3);
        }
        g_sys_nalpm_master[lchip]->route_stats[ip_ver][SYS_IPUC_ALPM]++;
        p_sys_ipuc_param->info->snake_idx = p_route_info->hw_position[0];
        p_sys_ipuc_param->info->entry_offset = p_route_info->hw_position[1] ;
    }

#ifdef IPUC_TEST_STUB
    {
        sys_nalpm_trie_payload_t* p_route_db_payload = NULL;
        p_route_db_payload = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_trie_payload_t));
        sal_memset(p_route_db_payload, 0 , sizeof(sys_nalpm_trie_payload_t));
        p_route_db_payload->p_route_info = p_route_info;
        sal_memcpy(key, p_route_info->ip, IP_ADDR_SIZE(ip_ver));
        sys_nalpm_trie_insert (g_sys_nalpm_master[lchip]->route_db_trie[ip_ver][p_route_info->vrf_id],
                               key, NULL, p_ipuc_param->masklen, (trie_node_t *) p_route_db_payload, 1);
    }
#endif
    return ret;

error3:
    sys_nalpm_trie_delete (p_tcam_item->trie, key, p_route_info->route_masklen, (trie_node_t **) &p_route_payload, 0);
error2:
    if(p_route_payload)
        mem_free(p_route_payload);
error1:
    if(p_route_info)
        mem_free(p_route_info);

    return ret;
}

int32
sys_tsingma_nalpm_del(uint8 lchip, void* p_sys_ipuc_param_v)
{
    sys_ipuc_param_t* p_sys_ipuc_param = (sys_ipuc_param_t*)p_sys_ipuc_param_v;
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm_route_info_t*  p_route_info = NULL;
    sys_nalpm_route_store_info_t lkp_rlt;
    sys_nalpm_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm_trie_payload_t* p_route_payload = NULL;
    sys_nalpm_prefix_trie_payload_t* p_pfx_payload = NULL;
    uint32 pfx_len = 0;
    uint32 key[4] = {0};
    uint8 ip_ver = 0;
    uint16 vrf_id = 0;
    int32 ret = CTC_E_NONE;


    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;

    if(p_ipuc_param->masklen== 0)
    {
        if(NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][p_ipuc_param->vrf_id])
        {
            return CTC_E_NOT_EXIST;
        }
        CTC_ERROR_RETURN(sys_tsingma_nalpm_update( lchip, p_sys_ipuc_param, INVALID_DRV_NEXTHOP_OFFSET));
        g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]--;
        if(g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id] == 0)
        {
            CTC_ERROR_RETURN( _sys_tsingma_nalpm_route_vrf_deinit(lchip, p_ipuc_param));
        }
        return ret;
    }
    /* prepare data */
    p_route_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_route_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_route_info, 0 , (ROUTE_INFO_SIZE(ip_ver)));
    p_route_info->ip_ver = ip_ver;
    sal_memcpy(p_route_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_route_info->route_masklen = p_ipuc_param->masklen;
    p_route_info->vrf_id = p_ipuc_param->vrf_id;
    SYS_IP_V6_SORT(p_route_info);

    /* 1. lookup sw node */
    ret = _sys_tsingma_nalpm_route_lkp( lchip, p_route_info,p_lkp_rlt);
    mem_free(p_route_info);
    if(ret < 0 || !p_lkp_rlt->sram_hit)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "can't find  route\n");
        return CTC_E_NOT_EXIST;
    }

    p_route_info = p_lkp_rlt->p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset];
     /* del route*/
    sal_memcpy(key , p_route_info->ip, IP_ADDR_SIZE(ip_ver));

    pfx_len = p_route_info->route_masklen;

    CTC_ERROR_RETURN(sys_nalpm_trie_delete (p_lkp_rlt->p_tcam_item->trie, key, pfx_len, (trie_node_t **) &p_route_payload, 1));

#ifdef IPUC_TEST_STUB
    {
        sys_nalpm_trie_payload_t* p_route_db_payload = NULL;
        sal_memcpy(key, p_route_info->ip, IP_ADDR_SIZE(ip_ver));
        sys_nalpm_trie_delete (g_sys_nalpm_master[lchip]->route_db_trie[ip_ver][p_route_info->vrf_id],
                               key, p_ipuc_param->masklen, (trie_node_t **) &p_route_db_payload, 1);
        mem_free(p_route_db_payload);
    }
#endif

    p_lkp_rlt->p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset] = NULL;
    CTC_ERROR_RETURN(_sys_nalpm_clear_sram(lchip, p_lkp_rlt->p_tcam_item, p_lkp_rlt->snake_idx, p_lkp_rlt->entry_offset, 1, NULL, NULL));

    g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]--;


    CTC_ERROR_RETURN(_sys_tsingma_nalpm_deletes_route_cover(lchip, p_lkp_rlt->p_tcam_item, p_route_payload->p_route_info, p_lkp_rlt->total_skip_len));
    mem_free(p_route_payload->p_route_info);
    mem_free(p_route_payload);

    CTC_BIT_UNSET(NALPM_BUCKET(lchip, p_lkp_rlt->p_tcam_item->sram_idx).bitmap[p_lkp_rlt->snake_idx], p_lkp_rlt->entry_offset);

    if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
    {
        /*update bucket*/
        CTC_ERROR_RETURN(_sys_tsingma_nalpm_bucket_list_update(lchip, p_lkp_rlt->p_tcam_item->sram_idx, -1));

    }


    if (!p_lkp_rlt->p_tcam_item->trie->trie)  /* sram entry is empty, release tcam*/
    {
        void *p_node1 = CONTAINER_OF(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id]->trie, sys_nalpm_prefix_trie_payload_t, node);
        void *p_node2 = CONTAINER_OF(p_lkp_rlt->p_tcam_item, sys_nalpm_prefix_trie_payload_t, tcam_item);
        if(p_node1 != p_node2)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)  sram entry is empty, release tcam\n",__LINE__);
            CTC_ERROR_RETURN(sys_nalpm_trie_destroy(p_lkp_rlt->p_tcam_item->trie));
            sal_memset(key, 0 , sizeof(key));
            sal_memcpy(key, p_lkp_rlt->p_tcam_item->p_prefix_info->ip, IP_ADDR_SIZE(ip_ver));
            CTC_ERROR_RETURN(sys_nalpm_trie_delete (g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id],
                                            key, p_lkp_rlt->p_tcam_item->p_prefix_info->tcam_masklen, (trie_node_t **) &p_pfx_payload, 0));
            CTC_ERROR_RETURN(_sys_tsingma_nalpm_write_tcam(lchip, p_lkp_rlt->p_tcam_item, DO_DEL, 0));
            CTC_ERROR_RETURN(_sys_tsingma_nalpm_tcam_idx_free(lchip, p_ipuc_param, p_lkp_rlt->p_tcam_item));
            CTC_ERROR_RETURN(_sys_tsingma_nalpm_sram_idx_free(lchip, p_lkp_rlt->p_tcam_item->sram_idx, ip_ver));

            mem_free(p_pfx_payload->tcam_item.p_prefix_info);
            mem_free(p_pfx_payload);
        }
    }


    if(g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id] == 0 || g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id]->trie == NULL)
    {
        CTC_ERROR_RETURN(_sys_tsingma_nalpm_route_vrf_deinit(lchip, p_ipuc_param));
    }
    g_sys_nalpm_master[lchip]->route_stats[ip_ver][SYS_IPUC_ALPM]--;




    return ret;
}

int32
sys_tsingma_nalpm_update(uint8 lchip, void* p_sys_ipuc_param_v, uint32 ad_index)
{
    sys_ipuc_param_t* p_sys_ipuc_param = (sys_ipuc_param_t*)p_sys_ipuc_param_v;
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm_route_info_t*  p_route_info = NULL;
    sys_nalpm_route_store_info_t lkp_rlt;
    sys_nalpm_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    uint8 ip_ver = 0;
    int32 ret = CTC_E_NONE;
    sys_nalpm_prefix_trie_payload_t* p_prefix_payload = NULL;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    if(p_ipuc_param->masklen == 0)
    {
        if (NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][p_ipuc_param->vrf_id])
        {
            return CTC_E_NOT_EXIST;
        }
        p_prefix_payload = CONTAINER_OF(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][p_ipuc_param->vrf_id]->trie, sys_nalpm_prefix_trie_payload_t, node);
        CTC_ERROR_RETURN(_sys_tsingma_nalpm_write_tcam( lchip, &(p_prefix_payload->tcam_item), DO_UPDATE, ad_index));
        CTC_ERROR_RETURN(_sys_tsingma_nalpm_default_route_cover(lchip, ip_ver, p_ipuc_param->vrf_id, ad_index));
        p_sys_ipuc_param->info->tcam_idx = p_prefix_payload->tcam_item.tcam_idx;
        p_prefix_payload->tcam_item.p_AD_route = (ad_index == INVALID_DRV_NEXTHOP_OFFSET) ? NULL :
                                                 (sys_nalpm_route_info_t*)p_sys_ipuc_param->info;
        /* only for /0 info for restore */
        return ret;
    }

    p_route_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_route_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_route_info, 0 , (ROUTE_INFO_SIZE(ip_ver)));
    p_route_info->ip_ver = ip_ver;
    sal_memcpy(p_route_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_route_info->route_masklen = p_ipuc_param->masklen;
    p_route_info->vrf_id = p_ipuc_param->vrf_id;
    p_route_info->ad_idx = ad_index;
    SYS_IP_V6_SORT(p_route_info);

    /* 1. lookup sw node */
    CTC_ERROR_GOTO(_sys_tsingma_nalpm_route_lkp( lchip, p_route_info,p_lkp_rlt), ret, error_proc);
    if(!p_lkp_rlt->sram_hit)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "(%d)   can't find  ip[%x]\n",__LINE__, p_route_info->ip[0]);
        ret = CTC_E_NOT_EXIST;
        goto error_proc;
    }
    p_lkp_rlt->p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset]->ad_idx = p_route_info->ad_idx;
    CTC_ERROR_GOTO(_sys_nalpm_write_sram( lchip, p_lkp_rlt->p_tcam_item, p_lkp_rlt->p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset],
                                         p_lkp_rlt->snake_idx, p_lkp_rlt->entry_offset, 1, NULL, NULL),
                   ret, error_proc);

    CTC_ERROR_GOTO(_sys_tsingma_nalpm_add_route_cover(lchip, p_lkp_rlt->p_tcam_item, p_lkp_rlt->p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset], 0, p_lkp_rlt->total_skip_len, 0, NULL), ret, error_proc);
error_proc:
    if(p_route_info)
        mem_free(p_route_info);

    return ret;
}

STATIC int32
_sys_tsingma_nalpm_free_route_node(trie_node_t * node, void *data)
{
    sys_nalpm_trie_payload_t* p_payload = NULL;
    sys_nalpm_route_info_t *p_ipuc_info = NULL;
    p_payload = (sys_nalpm_trie_payload_t* )node;
    if (p_payload->node.type != INTERNAL)
    {
        p_ipuc_info = p_payload->p_route_info;
        mem_free(p_ipuc_info);
    }
    mem_free(p_payload);
    return CTC_E_NONE;
}

STATIC int32
_sys_tsingma_nalpm_free_prefix_node(trie_node_t * p_node, void * user_data)
{
    sys_nalpm_prefix_trie_payload_t * p_prefix_trie_payload = NULL;
    p_prefix_trie_payload = CONTAINER_OF(p_node, sys_nalpm_prefix_trie_payload_t, node);
    if (p_node == NULL)
    {
        return CTC_E_NONE;
    }
    if (INTERNAL == p_prefix_trie_payload->node.type)
    {
        mem_free(p_prefix_trie_payload);
        return CTC_E_NONE;
    }
    sys_nalpm_trie_traverse(p_prefix_trie_payload->tcam_item.trie->trie, _sys_tsingma_nalpm_free_route_node, NULL, _TRIE_POSTORDER_TRAVERSE);
    mem_free(p_prefix_trie_payload->tcam_item.trie);
    mem_free(p_prefix_trie_payload->tcam_item.p_prefix_info);
    mem_free(p_prefix_trie_payload);
    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_deinit(uint8 lchip)
{
    uint8 ip_ver = 0;
    uint16 vrfid = 0;
    uint16 i = 0;

    if(NULL == g_sys_nalpm_master[lchip])
    {
        return CTC_E_NONE;
    }
    if(p_usw_ipuc_master[lchip]->master_lchip != lchip)
    {
        g_sys_nalpm_master[lchip] = NULL;
        return CTC_E_NONE;
    }

    for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
    {
        for (vrfid = 0; vrfid <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); vrfid++)
        {
            if (g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid] == NULL)
            {
                continue;
            }
            sys_nalpm_trie_traverse(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie, _sys_tsingma_nalpm_free_prefix_node, NULL, _TRIE_POSTORDER_TRAVERSE);
        }
    }
    for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
    {
        for (vrfid = 0; vrfid <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); vrfid++)
        {
            if (g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid] == NULL)
            {
                continue;
            }
            mem_free(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]);
        }
    }

    sys_usw_opf_deinit(lchip, g_sys_nalpm_master[lchip]->opf_type_nalpm);


    if (g_sys_nalpm_master[lchip]->bkt_use_list)
    {
        mem_free(g_sys_nalpm_master[lchip]->bkt_use_list);
    }

    if (g_sys_nalpm_master[lchip]->bucket)
    {
        for (i = 0; i < (g_sys_nalpm_master[lchip]->real_bkt_depth / NALPM_BUCKET_BSIZE + 1); i++)
        {
            if (NULL != g_sys_nalpm_master[lchip]->bucket[i])
            {
                mem_free(g_sys_nalpm_master[lchip]->bucket[i]);
            }
        }

        mem_free(g_sys_nalpm_master[lchip]->bucket);
    }

    mem_free(g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_4]);
    mem_free(g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6]);
    mem_free(g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_4]);
    mem_free(g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_6]);

    ctc_hash_free(g_sys_nalpm_master[lchip]->tcam_idx_hash);
    ctc_hash_free(g_sys_nalpm_master[lchip]->ipuc_cover_hash);
    mem_free(g_sys_nalpm_master[lchip]);

    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_init(uint8 lchip,  ctc_ipuc_global_cfg_t* p_ipuc_global_cfg, uint8 ipsa_enable)
{
    sys_usw_opf_t opf;
    uint16 i = 0, j = 0;
    uint32 cmd = 0;
    uint32 value = 0;
    uint32 lpm_pipeline_if_ctl[4/4] = {0};
    uint16 vrfid_num[MAX_CTC_IP_VER] = {0};
    uint32 entry_num = 0;
    uint32 max_size = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (g_sys_nalpm_master[lchip])
    {
        CTC_ERROR_RETURN(sys_tsingma_nalpm_deinit(lchip));
    }

    if(p_ipuc_global_cfg->master_lchip_valid && p_ipuc_global_cfg->master_lchip != lchip)
    {
        if(!g_sys_nalpm_master[p_ipuc_global_cfg->master_lchip])
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Master lchip must init first!! \n");
            return CTC_E_NOT_READY;
        }
        g_sys_nalpm_master[lchip] = g_sys_nalpm_master[p_ipuc_global_cfg->master_lchip];
        return CTC_E_NONE;
    }

    g_sys_nalpm_master[lchip] = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_master_t));
    if(NULL == g_sys_nalpm_master[lchip])
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(g_sys_nalpm_master[lchip], 0, sizeof(sys_nalpm_master_t));

    g_sys_nalpm_master[lchip]->ipuc_cover_hash = ctc_hash_create(1,
                            (IPUC_IPV6_HASH_MASK + 1),
                            (hash_key_fn)_sys_tsingma_ipuc_hash_make,
                            (hash_cmp_fn)_sys_tsingma_ipuc_hash_cmp);

    g_sys_nalpm_master[lchip]->tcam_idx_hash = ctc_hash_create(1,
                            (IPUC_IPV6_HASH_MASK + 1),
                            (hash_key_fn)_sys_tsingma_tcam_hash_make,
                            (hash_cmp_fn)_sys_tsingma_tcam_hash_cmp);

    g_sys_nalpm_master[lchip]->split_mode = 1;
    g_sys_nalpm_master[lchip]->ipsa_enable = ipsa_enable;

    g_sys_nalpm_master[lchip]->use_snake64 = (p_ipuc_global_cfg->prefix64_mode == CTC_IPUC_SHORT_V6_PREFIX_MODE ||
                                              p_ipuc_global_cfg->prefix64_mode == 3);

    if (p_ipuc_global_cfg->prefix64_mode == 2 ||
        p_ipuc_global_cfg->prefix64_mode == 3)
    {
        g_sys_nalpm_master[lchip]->ipv6_couple_mode = (SYS_GET_CHIP_VERSION == SYS_CHIP_SUB_VERSION_B && DRV_IS_TSINGMA(lchip)) ? 1 : 0;
    }

    if (g_sys_nalpm_master[lchip]->ipv6_couple_mode)
    {
        cmd = DRV_IOR(FibEngineReserved_t, FibEngineReserved_reserved_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
        value = value | 3;
        cmd = DRV_IOW(FibEngineReserved_t, FibEngineReserved_reserved_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
    }
    else
    {
        cmd = DRV_IOR(FibEngineReserved_t, FibEngineReserved_reserved_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
        value = 0;
        cmd = DRV_IOW(FibEngineReserved_t, FibEngineReserved_reserved_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
    }

    vrfid_num[CTC_IP_VER_4] = MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID)+1;
    vrfid_num[CTC_IP_VER_6] = MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID)+1;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "vrfid_num v4 [%u], v6 [%u]\n",vrfid_num[CTC_IP_VER_4], vrfid_num[CTC_IP_VER_6]);

    g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_4] = mem_malloc(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_4]);
    g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6] = mem_malloc(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_6]);
    g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_4] = mem_malloc(MEM_IPUC_MODULE, sizeof(uint32) * vrfid_num[CTC_IP_VER_4]);
    g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_6] = mem_malloc(MEM_IPUC_MODULE, sizeof(uint32) * vrfid_num[CTC_IP_VER_6]);

    if (!g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_4] || !g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6]
        || !g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_4] || !g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_6])
    {
        goto error0;
    }

    sal_memset(g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_4], 0, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_4]);
    sal_memset(g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6], 0, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_6]);
    sal_memset(g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_4], 0, sizeof(uint32) * vrfid_num[CTC_IP_VER_4]);
    sal_memset(g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_6], 0, sizeof(uint32) * vrfid_num[CTC_IP_VER_6]);



#ifdef IPUC_TEST_STUB
    g_sys_nalpm_master[lchip]->route_db_trie[CTC_IP_VER_4] = mem_malloc(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_4]);
    g_sys_nalpm_master[lchip]->route_db_trie[CTC_IP_VER_6] = mem_malloc(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_6]);
#endif

    /*SRAM idx*/
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    CTC_ERROR_RETURN(sys_usw_opf_init(lchip, &g_sys_nalpm_master[lchip]->opf_type_nalpm, 1, "opf-type-nalpm"));
    opf.pool_index = 0;
    opf.pool_type  = g_sys_nalpm_master[lchip]->opf_type_nalpm;
    CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, DsNeoLpmIpv4Bit32Snake_t, &entry_num));

    if (DRV_IS_TSINGMA(lchip))
    {
        g_sys_nalpm_master[lchip]->bkt_depth = entry_num;
        g_sys_nalpm_master[lchip]->snake_group_num = ipsa_enable?1:2;
        g_sys_nalpm_master[lchip]->snake_per_group = 1;
        g_sys_nalpm_master[lchip]->trie_merg_en  = 1;
    }
    else
    {
        g_sys_nalpm_master[lchip]->bkt_depth = 16*1024;
        g_sys_nalpm_master[lchip]->snake_group_num = ipsa_enable?1:2;
        g_sys_nalpm_master[lchip]->snake_per_group = (entry_num / g_sys_nalpm_master[lchip]->bkt_depth);

        g_sys_nalpm_master[lchip]->trie_merg_en  = 1;
        g_sys_nalpm_master[lchip]->bkt_mgr_en = 1;
    }

    MCHIP_CAP(SYS_CAP_SPEC_LPM_ROUTE_ENTRY_NUM) = g_sys_nalpm_master[lchip]->bkt_depth *
                                                  g_sys_nalpm_master[lchip]->snake_group_num *
                                                  g_sys_nalpm_master[lchip]->snake_per_group *
                                                  ROUTE_NUM_PER_SNAKE_V4;

    g_sys_nalpm_master[lchip]->real_bkt_depth =  g_sys_nalpm_master[lchip]->bkt_depth;
    max_size = g_sys_nalpm_master[lchip]->real_bkt_depth;

    g_sys_nalpm_master[lchip]->v6_mode = g_sys_nalpm_master[lchip]->snake_per_group == 5 ? 1 : 0;

    CTC_ERROR_RETURN(sys_usw_opf_init_offset(lchip, &opf, 0, max_size));


    g_sys_nalpm_master[lchip]->bucket = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_bucket_t *)*(max_size / NALPM_BUCKET_BSIZE + 1));
    if (NULL == g_sys_nalpm_master[lchip]->bucket)
    {
        goto error0;
    }

    sal_memset(g_sys_nalpm_master[lchip]->bucket, 0, sizeof(sys_nalpm_bucket_t *)*(max_size / NALPM_BUCKET_BSIZE + 1));

    for (i = 0; i < (max_size / NALPM_BUCKET_BSIZE + 1); i++)
    {
        g_sys_nalpm_master[lchip]->bucket[i] = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_bucket_t )*NALPM_BUCKET_BSIZE);
        if (NULL == g_sys_nalpm_master[lchip]->bucket[i])
        {
            goto error0;
        }

        sal_memset(g_sys_nalpm_master[lchip]->bucket[i], 0, sizeof(sys_nalpm_bucket_t)*NALPM_BUCKET_BSIZE);
    }

    if (g_sys_nalpm_master[lchip]->bkt_mgr_en)
    {
        entry_num = g_sys_nalpm_master[lchip]->snake_per_group* 2 *ROUTE_NUM_PER_SNAKE_V4 + 1;
        g_sys_nalpm_master[lchip]->bkt_use_list = mem_malloc(MEM_IPUC_MODULE, sizeof(ctc_list_pointer_t)*entry_num);
        if (NULL == g_sys_nalpm_master[lchip]->bkt_use_list)
        {
            goto error0;
        }
        for (i = 0; i < entry_num; i++)
        {
            ctc_list_pointer_init(&g_sys_nalpm_master[lchip]->bkt_use_list[i]);
        }

    }

    for (i = 0; i <= SYS_NALPM_V4_MASK_LEN_MAX ; i++)
    {
        for (j = 0; j < i ; j++)
        {
            g_sys_nalpm_master[lchip]->len2pfx[i] |= 1 << (SYS_NALPM_V4_MASK_LEN_MAX - 1 - j);
        }
    }

    if(DRV_IS_TSINGMA(lchip))
    {
#if defined(TSINGMA)
        g_sys_nalpm_master[lchip]->build_snake_cb[SYS_NALPM_SRAM_TYPE_V4_32]  = _sys_tsingama_nalpm_build_snake_ipv4_32;
        g_sys_nalpm_master[lchip]->build_snake_cb[SYS_NALPM_SRAM_TYPE_V6_64]  = _sys_tsingama_nalpm_build_snake_ipv6_64;
        g_sys_nalpm_master[lchip]->build_snake_cb[SYS_NALPM_SRAM_TYPE_V6_128] = _sys_tsingama_nalpm_build_snake_ipv6_128;
#endif
    }
    else
    {
#if defined(TSINGMA_MX)
        g_sys_nalpm_master[lchip]->build_snake_cb[SYS_NALPM_SRAM_TYPE_V4_EXT] = _sys_tmm_nalpm_build_snake_ext_ipv4_32_ext;
        g_sys_nalpm_master[lchip]->build_snake_cb[SYS_NALPM_SRAM_TYPE_V6_64]  = _sys_tmm_nalpm_build_snake_ipv6_64;
        g_sys_nalpm_master[lchip]->build_snake_cb[SYS_NALPM_SRAM_TYPE_V6_64_EXT] = _sys_tmm_nalpm_build_snake_ipv6_64;
        g_sys_nalpm_master[lchip]->build_snake_cb[SYS_NALPM_SRAM_TYPE_V6_LOW_64_EXT] = _sys_tmm_nalpm_build_snake_ipv6_64;
        g_sys_nalpm_master[lchip]->build_snake_cb[SYS_NALPM_SRAM_TYPE_V6_128] = _sys_tmm_nalpm_build_snake_ipv6_128;
#endif
    }

    cmd = DRV_IOR(LpmPipelineIfCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, lpm_pipeline_if_ctl));
    value = 1;
    DRV_IOW_FIELD(lchip, LpmPipelineIfCtl_t, LpmPipelineIfCtl_neoLpmEn_f, &value, lpm_pipeline_if_ctl);
    cmd = DRV_IOW(LpmPipelineIfCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, lpm_pipeline_if_ctl));

    /* disable fragment arrangement by default */
    g_sys_nalpm_master[lchip]->frag_arrange_enable = 0;
    /* For performance ,disable move hit */
    g_sys_nalpm_master[lchip]->move_hit_en = 1;

    return CTC_E_NONE;
error0:
    if (g_sys_nalpm_master[lchip]->bkt_use_list)
    {
        mem_free(g_sys_nalpm_master[lchip]->bkt_use_list);
    }

    if (g_sys_nalpm_master[lchip]->bucket)
    {
        for (i = 0; i < (max_size / NALPM_BUCKET_BSIZE + 1); i++)
        {
            if (NULL != g_sys_nalpm_master[lchip]->bucket[i])
            {
                mem_free(g_sys_nalpm_master[lchip]->bucket[i]);
            }
        }

        mem_free(g_sys_nalpm_master[lchip]->bucket);
    }


    if (g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_4])
    {
        mem_free(g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_4]);
    }
    if (g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6])
    {
        mem_free(g_sys_nalpm_master[lchip]->prefix_trie[CTC_IP_VER_6]);
    }
    if (g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_4])
    {
        mem_free(g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_4]);
    }
    if (g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_6])
    {
        mem_free(g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_6]);
    }
    if (g_sys_nalpm_master[lchip])
    {
        mem_free(g_sys_nalpm_master[lchip]);
    }
    return CTC_E_NO_MEMORY;
}

int32
_sys_tsingma_nalpm_wb_restore_route(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm_tcam_item_t* p_tcam_item)
{
    sys_nalpm_trie_payload_t* p_trie_route_info = NULL;
    sys_nalpm_route_info_t*  p_route_info = NULL;
    uint32 key[4] = {0};
    int32 ret = CTC_E_NONE;
    uint32 v6_temp = 0;
    uint16 vrf_id = p_tcam_item->p_prefix_info->vrf_id;
    uint16 sram_idx = p_tcam_item->sram_idx;
    uint8 ip_ver = p_tcam_item->p_prefix_info->ip_ver;
    uint8 snake_idx = p_sys_ipuc_param->info->snake_idx;
    uint8 entry_offset = p_sys_ipuc_param->info->entry_offset;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    p_trie_route_info = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm_trie_payload_t), sys_nalpm_trie_payload_t);
    if (NULL == p_trie_route_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        return CTC_E_NO_MEMORY;
    }

    p_route_info = mem_malloc2(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver), sys_nalpm_route_info_t);
    if (NULL == p_route_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        goto error0;
    }

    sal_memset(p_trie_route_info, 0, sizeof(sys_nalpm_trie_payload_t));
    sal_memset(p_route_info, 0, ROUTE_INFO_SIZE(ip_ver));

    /* 1. insert route trie */
    p_tcam_item->p_ipuc_info_array[snake_idx][entry_offset] = p_route_info;
    p_trie_route_info->p_route_info = p_route_info;
    p_route_info->ipuc_info = p_sys_ipuc_param->info;

    p_route_info->ad_idx = p_sys_ipuc_param->info->ad_index;
    p_route_info->hw_position[0] = snake_idx;
    p_route_info->hw_position[1] = entry_offset;
    p_route_info->vrf_id = vrf_id;
    p_route_info->tcam_masklen = p_tcam_item->p_prefix_info->tcam_masklen;
    p_route_info->route_masklen = p_sys_ipuc_param->info->masklen;
    p_route_info->ip_ver = ip_ver;
    sal_memcpy(p_route_info->ip, &(p_sys_ipuc_param->info->ip), IP_ADDR_SIZE(ip_ver));

    if (CTC_IP_VER_6 == ip_ver)
    {
        v6_temp = p_route_info->ip[0];
        p_route_info->ip[0] = p_route_info->ip[3];
        p_route_info->ip[3] = v6_temp;
        v6_temp = p_route_info->ip[1];
        p_route_info->ip[1] = p_route_info->ip[2];
        p_route_info->ip[2] = v6_temp;
    }

    sal_memcpy(key, p_route_info->ip, IP_ADDR_SIZE(ip_ver));
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(p_tcam_item->trie, key, NULL, p_sys_ipuc_param->info->masklen, (trie_node_t *)p_trie_route_info, 1), ret, error1);

    /* 2. restore bucket info */
    if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
    {
        _sys_tsingma_nalpm_bucket_list_update(lchip, sram_idx, 1);
    }
    CTC_BIT_SET(NALPM_BUCKET(lchip, sram_idx).bitmap[snake_idx], entry_offset);

    /* 3. restore stats */
    g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]++;
    g_sys_nalpm_master[lchip]->route_stats[ip_ver][SYS_IPUC_ALPM]++;

    return ret;

error1:
    if (p_route_info)
    {
        mem_free(p_route_info);
    }

error0:
    if (p_trie_route_info)
    {
        mem_free(p_trie_route_info);
    }

    return ret;
}

int32
_sys_tsingma_nalpm_wb_restore_prefix(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm_route_info_t* p_route_info)
{
    sys_nalpm_route_store_info_t lkp_rlt;
    sys_nalpm_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm_prefix_trie_payload_t *p_trie_tcam_item;
    sys_nalpm_route_info_t* p_prefix_info = NULL;
    sys_nalpm_tcam_item_t* p_tcam_item = NULL;
    sys_ipuc_tcam_key_t tcam_key;
    sys_ipuc_tcam_ad_t tcam_ad;
    sys_usw_opf_t opf;
    uint32 ip_null[4] = {0};
    int32 ret = CTC_E_NONE;
    uint32 v6_temp;
    uint16 tcam_idx = p_sys_ipuc_param->info->tcam_idx;
    uint16 vrf_id = p_sys_ipuc_param->info->vrf_id;
    uint8 ip_ver = p_route_info->ip_ver;
    uint8 block_size = 0;
    uint8 msl = ((ip_ver == CTC_IP_VER_4) ? SYS_NALPM_V4_MASK_LEN_MAX : SYS_NALPM_V6_MASK_LEN_MAX);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    p_trie_tcam_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm_prefix_trie_payload_t), sys_nalpm_prefix_trie_payload_t);
    if(NULL == p_trie_tcam_item)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        return CTC_E_NO_MEMORY;
    }

    p_prefix_info = mem_malloc2(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver), sys_nalpm_route_info_t);
    if(NULL == p_prefix_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        ret = CTC_E_NO_MEMORY;
        goto error0;
    }

    sal_memset(p_trie_tcam_item, 0, sizeof(sys_nalpm_prefix_trie_payload_t));
    sal_memset(p_lkp_rlt, 0, sizeof(sys_nalpm_route_store_info_t));
    sal_memset(p_prefix_info, 0, ROUTE_INFO_SIZE(ip_ver));
    sal_memset(&tcam_key, 0, sizeof(sys_ipuc_tcam_key_t));
    sal_memset(&tcam_ad, 0, sizeof(sys_ipuc_tcam_ad_t));
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));

    /* 1. init prefix trie */
    if (g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id] == 0)
    {
        CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id]), ret, error1);
    }

    /* 2. lookup prefix trie and check whether has tcam prefix */
    _sys_tsingma_nalpm_route_lkp(lchip, p_route_info, p_lkp_rlt);
    if (p_lkp_rlt->tcam_hit && p_lkp_rlt->p_tcam_item->tcam_idx == tcam_idx)
    {
        /* 2.1 is default route */
        if (p_sys_ipuc_param->info->masklen == 0)
        {
            g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]++;
            goto error1;
        }

        /* 2.2 restore route info */
        CTC_ERROR_GOTO(_sys_tsingma_nalpm_wb_restore_route(lchip, p_sys_ipuc_param, p_lkp_rlt->p_tcam_item), ret, error2);

        goto error1;
    }

    /* 3. read tcam */
    tcam_key.key_idx = tcam_idx;
    tcam_ad.tcamAd_key_idx = tcam_idx;
    sys_tsingma_ipuc_tcam_read_key(lchip, ip_ver, SYS_PRIVATE_MODE, &tcam_key);
    sys_tsingma_ipuc_tcam_read_ad(lchip, ip_ver, SYS_PRIVATE_MODE, &tcam_ad);

    /* 4. restore tcam item */
    p_tcam_item = &p_trie_tcam_item->tcam_item;
    p_tcam_item->tcam_idx = tcam_idx;
    p_tcam_item->sram_idx = (tcam_ad.pointer & 0x3fff);
    p_tcam_item->p_prefix_info = p_prefix_info;
    p_tcam_item->sub_bkt = (tcam_ad.pointer >> 16) & 0x1;
    _sys_tsingma_nalpm_set_sram_type(lchip, ip_ver, p_sys_ipuc_param->info->masklen, p_tcam_item);
    CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &(p_tcam_item->trie)), ret, error2);

    /* 5. restore opf index */
    opf.pool_index = 0;
    if(DRV_IS_TSINGMA(lchip))
    {
        if (ip_ver && g_sys_nalpm_master[lchip]->ipv6_couple_mode)
        {
            opf.multiple = 8;
            block_size = 8;
        }
        else
        {
            opf.multiple = 4;
            block_size = 4;
        }
    }
    else
    {
        opf.multiple = 1;
        block_size = 1;
    }
    opf.pool_type = g_sys_nalpm_master[lchip]->opf_type_nalpm;

    sys_usw_opf_alloc_offset_from_position(lchip, &opf, block_size, p_tcam_item->sram_idx);

    /* 6. restore l0 root info */
    p_prefix_info->ad_idx = tcam_ad.nexthop;
    p_prefix_info->ip_ver = ip_ver;
    p_prefix_info->vrf_id = vrf_id;
    p_prefix_info->tcam_masklen = tcam_key.mask_len;
    sal_memcpy(p_prefix_info->ip, &tcam_key.ip, IP_ADDR_SIZE(ip_ver));

    CTC_ERROR_GOTO(_sys_tsingma_nalpm_tcam_idx_alloc(lchip, &p_sys_ipuc_param->param, p_tcam_item), ret, error3);

    /* 7. insert prefix trie */
    if (CTC_IP_VER_6 == ip_ver)
    {
        if(IS_SHORT_KEY(SYS_PRIVATE_MODE, tcam_idx))
        {
            v6_temp = p_tcam_item->p_prefix_info->ip[0];
            p_tcam_item->p_prefix_info->ip[0] = p_tcam_item->p_prefix_info->ip[1];
            p_tcam_item->p_prefix_info->ip[1] = v6_temp;
        }
        else
        {
            v6_temp = p_tcam_item->p_prefix_info->ip[0];
            p_tcam_item->p_prefix_info->ip[0] = p_tcam_item->p_prefix_info->ip[3];
            p_tcam_item->p_prefix_info->ip[3] = v6_temp;
            v6_temp = p_tcam_item->p_prefix_info->ip[1];
            p_tcam_item->p_prefix_info->ip[1] = p_tcam_item->p_prefix_info->ip[2];
            p_tcam_item->p_prefix_info->ip[2] = v6_temp;
        }
    }

    SYS_NALPM_CONVERT_TO_LSB(p_tcam_item->p_prefix_info->ip, p_tcam_item->p_prefix_info->tcam_masklen, ip_ver);
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id], p_tcam_item->p_prefix_info->ip, NULL, p_tcam_item->p_prefix_info->tcam_masklen, (trie_node_t *)p_trie_tcam_item, 0), ret, error4);

    /* 8. restore bucket */
    NALPM_BUCKET(lchip, p_tcam_item->sram_idx).sram_idx = p_tcam_item->sram_idx;

    if (NALPM_BUCKET_MGR_EN(lchip, ip_ver))
    {
        if (p_tcam_item->sub_bkt == 1)
        {
            NALPM_BUCKET_SUB_BKT(lchip, p_tcam_item->sram_idx) = 2;
        }
        else if(NALPM_BUCKET_SUB_BKT(lchip, p_tcam_item->sram_idx) != 2)
        {
            NALPM_BUCKET_SUB_BKT(lchip, p_tcam_item->sram_idx) = 1;
        }
    }

    if (!sal_memcmp(ip_null, p_tcam_item->p_prefix_info->ip, IP_ADDR_SIZE(ip_ver)))
    {
        NALPM_BUCKET(lchip, p_tcam_item->sram_idx).is_root = 1;
    }

    /* 9. insert route trie */
    if (p_sys_ipuc_param->info->masklen)
    {
        CTC_ERROR_GOTO(_sys_tsingma_nalpm_wb_restore_route(lchip, p_sys_ipuc_param, p_tcam_item), ret, error5);
    }
    else
    {
        g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]++;
    }

    return ret;

error5:
    sys_nalpm_trie_delete(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id], p_tcam_item->p_prefix_info->ip, p_tcam_item->p_prefix_info->tcam_masklen, (trie_node_t **)&p_trie_tcam_item, 0);

error4:
    _sys_tsingma_nalpm_tcam_idx_free(lchip, &p_sys_ipuc_param->param, p_tcam_item);

error3:
    sys_nalpm_trie_destroy(p_tcam_item->trie);
    p_tcam_item->trie = NULL;

error2:
    sys_nalpm_trie_destroy(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id]);
    g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id] = NULL;

error1:
    if (p_prefix_info)
    {
        mem_free(p_prefix_info);
    }

error0:
    if (p_trie_tcam_item)
    {
        mem_free(p_trie_tcam_item);
    }

    return ret;
}

int32
sys_tsingma_nalpm_wb_get_info(uint8 lchip, void* p_ipuc_param_v, void* p_alpm_info)
{
    sys_wb_nalpm_info_t* p_wb_nalpm_info = (sys_wb_nalpm_info_t*)p_alpm_info;
    sys_nalpm_route_info_t*  p_route_info = NULL;
    sys_nalpm_route_store_info_t lkp_rlt;
    uint8 ip_ver = 0;
    int32 ret = CTC_E_NONE;
    ctc_ipuc_param_t* p_ipuc_param = (ctc_ipuc_param_t*)p_ipuc_param_v;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_NALPM_INIT_CHECK;

    ip_ver = p_ipuc_param->ip_ver;
    p_route_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_route_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_route_info, 0 , (ROUTE_INFO_SIZE(ip_ver)));
    p_route_info->ip_ver = ip_ver;
    sal_memcpy(p_route_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_route_info->route_masklen = p_ipuc_param->masklen;
    p_route_info->vrf_id = p_ipuc_param->vrf_id;
    SYS_IP_V6_SORT(p_route_info);

    sal_memset(&lkp_rlt, 0 , sizeof(sys_nalpm_route_store_info_t));
    ret = _sys_tsingma_nalpm_route_lkp(lchip, p_route_info, &lkp_rlt);
    mem_free(p_route_info);
    if(!lkp_rlt.tcam_hit || lkp_rlt.p_tcam_item == NULL)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- tcam not hit\r\n", __LINE__);
        return CTC_E_NOT_EXIST;
    }
    if(!lkp_rlt.sram_hit && p_ipuc_param->masklen > 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- sram not hit\r\n", __LINE__);
        return  CTC_E_NOT_EXIST;
    }

    p_wb_nalpm_info->tcam_idx = lkp_rlt.p_tcam_item->tcam_idx;
    p_wb_nalpm_info->snake_idx= lkp_rlt.snake_idx;
    p_wb_nalpm_info->entry_offset = lkp_rlt.entry_offset;
    return ret;
}

void
_sys_tsingma_nalpm_wb_mapping_prefix(sys_nalpm_tcam_item_t* p_tcam_item, sys_wb_nalpm_prefix_info_t* p_wb_prefix_info, sys_nalpm_tcam_ad_t* p_tcam_ad, uint8 is_sync)
{
    if (is_sync)
    {
        p_wb_prefix_info->tcam_idx = p_tcam_item->tcam_idx;
        p_wb_prefix_info->ad_route_masklen = p_tcam_item->p_AD_route->route_masklen;
        p_wb_prefix_info->ip_ver = p_tcam_item->p_AD_route->ip_ver;
        sal_memcpy(p_wb_prefix_info->ad_route_addr, p_tcam_item->p_AD_route->ip, IP_ADDR_SIZE(p_wb_prefix_info->ip_ver));
    }
    else
    {
        p_tcam_ad->tcam_idx = p_wb_prefix_info->tcam_idx;
        p_tcam_ad->masklen = p_wb_prefix_info->ad_route_masklen;
        sal_memcpy(p_tcam_ad->ip, p_wb_prefix_info->ad_route_addr, IP_ADDR_SIZE(p_wb_prefix_info->ip_ver));
    }

    return;
}

int32
_sys_tsingma_nalpm_wb_prefix_sync(trie_node_t * p_node, void * user_data)
{
    uint32 max_entry_cnt = 0;
    sys_wb_nalpm_prefix_info_t  *p_wb_prefix_info;
    sys_traverse_t *data = (sys_traverse_t *)user_data;
    ctc_wb_data_t *wb_data = (ctc_wb_data_t *)(data->data);
    sys_nalpm_prefix_trie_payload_t* p_payload = (sys_nalpm_prefix_trie_payload_t* )p_node;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = data->value1;
#endif
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    if (p_node->type == INTERNAL)
    {
         return CTC_E_NONE;
    }

    if (p_payload->tcam_item.p_prefix_info->tcam_masklen == 0 || !p_payload->tcam_item.p_AD_route)
    {
        return CTC_E_NONE;
    }

    max_entry_cnt = wb_data->buffer_len / (wb_data->key_len + wb_data->data_len);

    p_wb_prefix_info = (sys_wb_nalpm_prefix_info_t *)wb_data->buffer + wb_data->valid_cnt;

    p_wb_prefix_info->lchip = data->value1;
    _sys_tsingma_nalpm_wb_mapping_prefix(&p_payload->tcam_item, p_wb_prefix_info, NULL, 1);
    if (++wb_data->valid_cnt == max_entry_cnt)
    {
        CTC_ERROR_RETURN(ctc_wb_add_entry(wb_data));
        wb_data->valid_cnt = 0;
    }

    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_wb_traverse_route_trie(trie_node_t* node, void* data)
{
    sys_nalpm_prefix_trie_payload_t* p_trie_tcam_item = (sys_nalpm_prefix_trie_payload_t*)node;
    sys_nalpm_tcam_item_t* p_tcam_item = &p_trie_tcam_item->tcam_item;
    int32 ret = CTC_E_NONE;
    uint16 tcam_index = 0;
    uint8 i, j;

    if (node->type == INTERNAL)
    {
         return CTC_E_NONE;
    }

    if (p_tcam_item)
    {
        tcam_index = p_tcam_item->tcam_idx;
    }

    i = 0;
    do
    {
        j = 0;
        do
        {
            if (NULL == p_tcam_item->p_ipuc_info_array[i][j])
            {
                j++;
                continue;
            }

            p_tcam_item->p_ipuc_info_array[i][j]->ipuc_info->tcam_idx = tcam_index;

            j++;

        } while (j < ROUTE_NUM_PER_SNAKE_V4);

        i++;

    } while (i < SYS_NALPM_MAX_SNAKE);

    return ret;
}

int32
_sys_tsingma_nalpm_wb_traverse_set_ad(trie_node_t* node, void* data)
{
    sys_nalpm_prefix_trie_payload_t* p_trie_tcam_item = (sys_nalpm_prefix_trie_payload_t*)node;
    trie_dump_node_t* p_dump_node = (trie_dump_node_t*)data;
    sys_nalpm_route_store_info_t lkp_rlt;
    sys_nalpm_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm_tcam_item_t* p_tcam_item = &p_trie_tcam_item->tcam_item;
    sys_nalpm_tcam_ad_t* p_tcam_ad = NULL;
    sys_nalpm_tcam_ad_t tcam_ad = {0};
    sys_nalpm_route_info_t* p_route_info;
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = 0;
    uint8 lchip = p_dump_node->lchip;

    if (node->type == INTERNAL)
    {
         return CTC_E_NONE;
    }

    ip_ver = p_tcam_item->p_prefix_info->ip_ver;

    tcam_ad.tcam_idx = p_tcam_item->tcam_idx;
    p_tcam_ad = ctc_hash_lookup(g_sys_nalpm_master[lchip]->tcam_idx_hash, &tcam_ad);
    if (NULL == p_tcam_ad)
    {
        return ret;
    }

    p_route_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_route_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_route_info, 0, (ROUTE_INFO_SIZE(ip_ver)));

    p_route_info->ip_ver = ip_ver;
    p_route_info->route_masklen = p_tcam_ad->masklen;
    p_route_info->vrf_id = p_tcam_item->p_prefix_info->vrf_id;
    sal_memcpy(p_route_info->ip, p_tcam_ad->ip, IP_ADDR_SIZE(ip_ver));

    _sys_tsingma_nalpm_route_lkp(lchip, p_route_info, p_lkp_rlt);

    if (p_lkp_rlt->sram_hit)
    {
        p_tcam_item->p_AD_route = p_lkp_rlt->p_tcam_item->p_ipuc_info_array[p_lkp_rlt->snake_idx][p_lkp_rlt->entry_offset];
    }

    if (p_route_info)
    {
        mem_free(p_route_info);
    }

    return ret;
}

int32
sys_tsingma_nalpm_wb_set_tcam_index(uint8 lchip)
{
    trie_dump_node_t dump_node = {0};
    sys_nalpm_prefix_trie_payload_t* p_prefix_payload = NULL;
    sys_ipuc_info_t* p_ipuc_info = NULL;
    int32 ret = CTC_E_NONE;
    uint16 vrfid = 0;
    uint8 ip_ver = 0;

    ip_ver = 0;
    do
    {
        vrfid = 0;
        do
        {
            if (NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid])
            {
                vrfid++;
                continue;
            }

            ret = sys_nalpm_trie_traverse(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie,
                                      _sys_tsingma_nalpm_wb_traverse_route_trie, &dump_node, _TRIE_DUMP_TRAVERSE);
            p_prefix_payload = CONTAINER_OF(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie, sys_nalpm_prefix_trie_payload_t, node);
            if(p_prefix_payload->tcam_item.p_AD_route)
            {
                p_ipuc_info = (sys_ipuc_info_t*)p_prefix_payload->tcam_item.p_AD_route;
                p_ipuc_info->tcam_idx = p_prefix_payload->tcam_item.tcam_idx;
            }
            vrfid++;

        } while (vrfid <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));

        ip_ver++;

    } while (ip_ver < MAX_CTC_IP_VER);

    return ret;
}

int32
sys_tsingma_nalpm_wb_set_ad_info(uint8 lchip)
{
    trie_dump_node_t dump_node = {0};
    int32 ret = CTC_E_NONE;
    uint16 vrfid = 0;
    uint8 ip_ver = 0;

    dump_node.lchip = lchip;

    ip_ver = 0;
    do
    {
        vrfid = 0;
        do
        {

            if (NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid] ||
                NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie)
            {
                vrfid++;
                continue;
            }

            ret = sys_nalpm_trie_traverse(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie,
                                      _sys_tsingma_nalpm_wb_traverse_set_ad, &dump_node, _TRIE_DUMP_TRAVERSE);

            vrfid++;

        } while (vrfid <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));

        ip_ver++;

    } while (ip_ver < MAX_CTC_IP_VER);

    ctc_hash_traverse(g_sys_nalpm_master[lchip]->tcam_idx_hash, (hash_traversal_fn)_sys_tsingma_nalpm_hash_free_node_data, &lchip);

    return ret;
}

int32
sys_tsingma_nalpm_wb_prefix_sync(uint8 lchip,uint32 app_id, void *p_temp_wb_data)
{
    sys_traverse_t user_data;
    uint16 i = 0, j = 0;
    ctc_wb_data_t* p_wb_data = p_temp_wb_data;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    if (app_id != 0 && CTC_WB_SUBID(app_id) != SYS_WB_APPID_IPUC_SUBID_INFO1)
    {
        return CTC_E_NONE;
    }
    if(NULL == g_sys_nalpm_master[lchip])
    {
        return CTC_E_NONE;
    }

    CTC_WB_INIT_DATA_T(p_wb_data, sys_wb_nalpm_prefix_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1);
    user_data.data = p_wb_data;

    p_wb_data->valid_cnt = 0;

    user_data.value1 = lchip;
    for(i = 0; i <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); i++)
    {
        for (j = 0; j < 2; j++)
        {
            if (NULL == g_sys_nalpm_master[lchip]->prefix_trie[j][i])
            {
                continue;
            }
            CTC_ERROR_RETURN(sys_nalpm_trie_traverse (g_sys_nalpm_master[lchip]->prefix_trie[j][i]->trie, _sys_tsingma_nalpm_wb_prefix_sync,(void *)&user_data, _TRIE_PREORDER_TRAVERSE));
        }
    }
    if (p_wb_data->valid_cnt > 0)
    {
        CTC_ERROR_RETURN(ctc_wb_add_entry(p_wb_data));
    }
    CTC_WB_SYNC_END_DATA(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1);

    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_wb_prefix_restore(uint8 lchip)
{
    sys_wb_nalpm_prefix_info_t wb_prefix_info;
    sys_nalpm_tcam_ad_t* p_tcam_ad = NULL;
    ctc_wb_query_t wb_query;
    int32 ret = CTC_E_NONE;
    uint32 entry_cnt = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&wb_query, 0, sizeof(ctc_wb_query_t));
    CTC_WB_ALLOC_BUFFER(&wb_query.buffer);

    CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_nalpm_prefix_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1);
    CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));

    sal_memcpy(&wb_prefix_info, (sys_wb_nalpm_prefix_info_t *)wb_query.buffer + entry_cnt++, wb_query.key_len + wb_query.data_len);

    p_tcam_ad = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm_tcam_ad_t), sys_nalpm_tcam_ad_t);
    if (NULL == p_tcam_ad)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_tcam_ad, 0, sizeof(sys_nalpm_tcam_ad_t));

    _sys_tsingma_nalpm_wb_mapping_prefix(NULL, &wb_prefix_info, p_tcam_ad, 0);

    if (NULL == ctc_hash_insert(g_sys_nalpm_master[wb_prefix_info.lchip]->tcam_idx_hash, p_tcam_ad))
    {
        goto error_proc;
    }

    CTC_WB_QUERY_ENTRY_END((&wb_query));

    goto done;

error_proc:
    if (p_tcam_ad)
    {
        mem_free(p_tcam_ad);
    }

done:
    if (wb_query.key)
    {
        mem_free(wb_query.key);
    }

    CTC_WB_FREE_BUFFER(wb_query.buffer)

    return ret;
}

#define SYS_IPUC_MASK_LEN 5
#define NALPM_GEN_IP_STR(buf, ip_ver, ip, mask) do{\
    char buf2[SYS_IPUC_MASK_LEN] = {0};\
    sal_sprintf(buf2, "/%d", mask);\
    if(ip_ver == CTC_IP_VER_4)\
    {\
        uint32 tempip = sal_ntohl(ip[0]);\
        sal_inet_ntop(AF_INET, &tempip, buf, CTC_IPV6_ADDR_STR_LEN);\
        sal_strncat(buf, buf2, SYS_IPUC_MASK_LEN);\
    }\
    else\
    {\
	    uint32 ipv6_address[4] = {0, 0, 0, 0};\
	    ipv6_address[0] = sal_ntohl(ip[0]);\
	    ipv6_address[1] = sal_ntohl(ip[1]);\
	    ipv6_address[2] = sal_ntohl(ip[2]);\
	    ipv6_address[3] = sal_ntohl(ip[3]);\
	    sal_inet_ntop(AF_INET6, ipv6_address, buf, CTC_IPV6_ADDR_STR_LEN);\
	    sal_strncat(buf, buf2, SYS_IPUC_MASK_LEN);\
    }\
}while(0);


int32
_sys_tsingma_nalpm_dump_route(uint8 lchip, uint8 i, sys_nalpm_route_info_t* p_ipuc_data)
{
    char buf[CTC_IPV6_ADDR_STR_LEN]={0};
    NALPM_GEN_IP_STR(buf, p_ipuc_data->ip_ver, p_ipuc_data->ip, p_ipuc_data->route_masklen);

    if (p_ipuc_data->ip_ver == CTC_IP_VER_4)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "[%-2d,%-2d] %-28s\n", p_ipuc_data->hw_position[0], p_ipuc_data->hw_position[1], buf);
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "[%-2d,%-2d] %-44s\n", p_ipuc_data->hw_position[0], p_ipuc_data->hw_position[1], buf);
    }

    return 0;
}

int32
_sys_tsingma_nalpm_dump_route_trie_node(trie_node_t * node, void *data)
{
    trie_node_t * trie = node;
    sys_nalpm_trie_payload_t* p_payload = NULL;
    sys_nalpm_route_info_t *p_ipuc_info = NULL;
    trie_dump_node_t *p_dump_node = (trie_dump_node_t *)data;
    uint32 level = p_dump_node->father_lvl;
    trie_node_t *p_father = p_dump_node->father;
    trie_node_t *p_root = p_dump_node->root;
    char* node_type_str[3] = {"T", "L", "R"};
    uint32 node_type = 0;
    char bit_str[32] = { 0 };
    char buf[CTC_IPV6_ADDR_STR_LEN];
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = p_dump_node->lchip;
#endif
    if (NULL == trie)
    {
        return CTC_E_NONE;
    }

    if (p_root == trie) /*root_node*/
    {
        node_type = 0;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    }
    else if (p_father->child[0].child_node == trie)
    {
        node_type = 1;
    }
    else
    {
        node_type = 2;
    }

    p_payload = (sys_nalpm_trie_payload_t* )node;

    while (level-- != 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    ");
    }

    sal_memset(bit_str, 0, sizeof(bit_str));
    NALPM_PFX2BITS(trie->skip_addr, trie->skip_len, bit_str);
    if (trie->type == PAYLOAD)
    {
        p_ipuc_info = p_payload->p_route_info;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
        "%s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p],",
         node_type_str[node_type], p_dump_node->father_lvl, trie,"P",
         trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
         trie->child[1].child_node);
         NALPM_GEN_IP_STR(buf, p_ipuc_info->ip_ver, p_ipuc_info->ip, p_ipuc_info->route_masklen);
         SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s\n", buf);
         SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "AD-idx:[0x%x]\n", p_ipuc_info->ad_idx);
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
        "%s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p]\n",
        node_type_str[node_type], p_dump_node->father_lvl, trie,"I",
        trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
        trie->child[1].child_node);
    }

    return CTC_E_NONE;
}

int32
_sys_tsingma_nalpm_dump_pfx_trie_node(trie_node_t * node, void *data)
{
    trie_node_t * trie = node;
    sys_nalpm_prefix_trie_payload_t* p_payload = NULL;
    sys_nalpm_route_info_t *p_ipuc_info = NULL;
    trie_dump_node_t *p_dump_node = (trie_dump_node_t *)data;
    uint32 level = p_dump_node->father_lvl;
    trie_node_t *p_father = p_dump_node->father;
    trie_node_t *p_root = p_dump_node->root;
    char* node_type_str[3] = {"T", "L", "R"};
    uint32 node_type = 0;
    char bit_str[32] = { 0 };
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = p_dump_node->lchip;
#endif
    if (NULL == trie)
    {
        return CTC_E_NONE;
    }

    if (p_root == trie) /*root_node*/
    {
        node_type = 0;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    }
    else if (p_father->child[0].child_node == trie)
    {
        node_type = 1;
    }
    else
    {
        node_type = 2;
    }

    p_payload = (sys_nalpm_prefix_trie_payload_t* )node;
    p_ipuc_info = p_payload->tcam_item.p_prefix_info;

    while (level-- != 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    ");
    }

    sal_memset(bit_str, 0, sizeof(bit_str));
    NALPM_PFX2BITS(trie->skip_addr, trie->skip_len, bit_str);
    if (trie->type == PAYLOAD)
    {
        if(p_ipuc_info == NULL)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "p_ipuc_info == NULL\n");
            return CTC_E_NONE;
        }
        if (CTC_IP_VER_4 == p_ipuc_info->ip_ver)
        {

            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
                             "tcam_idx[%u], %s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p], pfx_IPv4[0x%x/%d]\n",
                             p_payload->tcam_item.tcam_idx , node_type_str[node_type], p_dump_node->father_lvl, trie, (trie->type == PAYLOAD) ? "P" : "I",
                             trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
                             trie->child[1].child_node,
                             p_ipuc_info->ip[0], p_ipuc_info->tcam_masklen);
        }
        else
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
                             "tcam_idx[%u], %s%d[%p], type[%s], skip_addr/len[0x%x/%d], cnt[%d] Child[%p/%p], pfx_IPv6[0x%x:0x%x:0x%x:0x%x/%d], trie[%p], &trie->skip_len[%d], &child[%p]\n",
                             //"tcam_idx[%u], %s%d[%p], type[%s], skip_addr/len[0x%x/%d], cnt[%d] Child[%p/%p], pfx_IPv6[0x%x:0x%x:0x%x:0x%x/%d]\n",
                             p_payload->tcam_item.tcam_idx , node_type_str[node_type], p_dump_node->father_lvl, trie, (trie->type == PAYLOAD) ? "P" : "I",
                             trie->skip_addr, trie->skip_len, trie->count, trie->child[0].child_node,
                             trie->child[1].child_node,
                             p_ipuc_info->ip[0],
                             p_ipuc_info->ip[1],
                             p_ipuc_info->ip[2],
                             p_ipuc_info->ip[3],
                             p_ipuc_info->tcam_masklen,
                             trie, trie->skip_len, trie->child);
        }
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
        "%s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p]\n",
         node_type_str[node_type], p_dump_node->father_lvl, trie, (trie->type == PAYLOAD) ? "P" : "I",
         trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
         trie->child[1].child_node);
    }

    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_dump_pfx_trie(uint8 lchip, uint16 vrfid, uint8 ip_ver)
{
    trie_dump_node_t dump_node;
    int32 ret = CTC_E_NONE;

    LCHIP_CHECK(lchip);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_NALPM_INIT_CHECK;

    CTC_MAX_VALUE_CHECK(ip_ver, CTC_IP_VER_6);
    CTC_MAX_VALUE_CHECK(vrfid, MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));

    SYS_IPUC_LOCK;

    if(NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid])
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]---[%p] \r\n", __LINE__, &g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]);
        SYS_IPUC_UNLOCK;
        return ret;
    }
    if(NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        SYS_IPUC_UNLOCK;
        return ret;
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"-----------prefix num:[%u]----total route[%u]------\n",
                        g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie->count,
                        g_sys_nalpm_master[lchip]->vrf_route_cnt[ip_ver][vrfid]);

    dump_node.father = g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie;
    dump_node.father_lvl = 0;
    dump_node.root =  g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie;

    ret = sys_nalpm_trie_traverse(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie, _sys_tsingma_nalpm_dump_pfx_trie_node, &dump_node, _TRIE_DUMP_TRAVERSE);

    SYS_IPUC_UNLOCK;
    return ret;
}


struct sys_nalpm_dump_route_info_s
{
    sys_nalpm_route_info_t* p_route_info;
    uint16 index;
    uint8 mode;
    uint8 detail;
}
;
typedef struct sys_nalpm_dump_route_info_s sys_nalpm_dump_route_info_t;


int32
_sys_tsingma_nalpm_dump_route_trie(trie_node_t * node, void *data)
{
    trie_dump_node_t *p_dump_node = (trie_dump_node_t*)data;
    sys_nalpm_dump_route_info_t* p_dump = (sys_nalpm_dump_route_info_t*)p_dump_node->user_data;
    sys_nalpm_prefix_trie_payload_t* p_payload = NULL;
    sys_nalpm_tcam_item_t* p_tcam_item =NULL;
    sys_nalpm_route_info_t* p_prefix = NULL;
    trie_dump_node_t dump_node;
    int32 ret = CTC_E_NONE;
    sys_nalpm_route_info_t* ad_route = NULL;
    uint8 lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    lchip = p_dump_node->lchip;
    if (PAYLOAD != node->type || NULL == p_dump)
    {
        return 0;
    }
    p_payload = (sys_nalpm_prefix_trie_payload_t*)node;
    p_tcam_item = &p_payload->tcam_item;
    p_prefix = p_tcam_item->p_prefix_info;

    if (p_tcam_item->trie == NULL)
    {
        return 0;
    }

    if (p_dump->mode == 0 && p_dump->index != p_tcam_item->tcam_idx)
    {
        return 0;
    }
    else if(p_dump->mode == 1 && p_dump->index != p_tcam_item->sram_idx)
    {
        return 0;
    }
    else if (p_dump->mode == 2)
    {
        uint8 i = 0;
        uint8 j = 0;
        uint8 found = 0;

        for (i = 0; i < SYS_NALPM_MAX_SNAKE; i++)
        {
            for (j = 0; j < ROUTE_NUM_PER_SNAKE_V4; j++)
            {
                if (NULL == p_tcam_item->p_ipuc_info_array[i][j])
                {
                    continue;
                }

                /*entry exist, find exact route*/
                if (0 == _sys_tsingma_nalpm_route_cmp(p_dump->p_route_info, p_tcam_item->p_ipuc_info_array[i][j]))
                {
                    found = 1;
                    break;
                }
            }

            if (found == 1)
            {
                break;
            }
        }

        if (found == 0)
        {
            return 0;
        }
    }

     if(p_dump->detail == 0)
      {
        uint8 i = 0;
        uint8 j = 0;
        uint8 cnt = 0;
        char buf[CTC_IPV6_ADDR_STR_LEN];
        uint32 ip[4] = {0};

        SYS_NALPM_CONVERT_TO_MSB(p_prefix->ip, p_prefix->tcam_masklen, ip, p_prefix->ip_ver);
        NALPM_GEN_IP_STR(buf, p_prefix->ip_ver, ip, p_prefix->tcam_masklen)

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n\nTcam Index: %4d\n", p_tcam_item->tcam_idx);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Sram Index: %4d Sub:%d\n", p_tcam_item->sram_idx, p_tcam_item->sub_bkt);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Prefix: %s %d\n", buf, p_tcam_item->p_prefix_info->vrf_id);

        if (p_tcam_item->p_prefix_info->tcam_masklen && p_tcam_item->p_AD_route)
        {
            NALPM_GEN_IP_STR(buf, p_prefix->ip_ver, p_tcam_item->p_AD_route->ip, p_tcam_item->p_AD_route->route_masklen)
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "*AD Route: %s\n", buf);
        }

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "==================================\n");

        for (i = 0; i < SYS_NALPM_MAX_SNAKE; i++)
        {
            for (j = 0; j < ROUTE_NUM_PER_SNAKE_V4; j++)
            {
                if (NULL == p_tcam_item->p_ipuc_info_array[i][j])
                {
                    continue;
                }
                _sys_tsingma_nalpm_dump_route(lchip, cnt++, p_tcam_item->p_ipuc_info_array[i][j]);

            }
        }

        if (NALPM_BUCKET_MGR_EN(lchip, p_prefix->ip_ver))
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Sram Used Entry: %d\n", NALPM_BUCKET_USE_CNT(lchip, p_tcam_item->sram_idx));
        }

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Total Entry: %d\n", cnt);
    }
    else
    {
        dump_node.lchip = lchip;
        dump_node.father = p_tcam_item->trie->trie;
        dump_node.father_lvl = 0;
        dump_node.root =  p_tcam_item->trie->trie;
        if (NULL == p_tcam_item->trie->trie)
        {
            return ret;
        }
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------AD route----------\n");
        ad_route = p_tcam_item->p_prefix_info->tcam_masklen ? p_tcam_item->p_AD_route : NULL;
        if(ad_route != NULL)
        {
            if (CTC_IP_VER_4 == ad_route->ip_ver)
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " pfx_IPv4[0x%x/%d]\n", ad_route->ip[0], ad_route->route_masklen);
            }
            else
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " pfx_IPv6[0x%x:0x%x:0x%x:0x%x/%d]\n",
                                 ad_route->ip[0],
                                 ad_route->ip[1],
                                 ad_route->ip[2],
                                 ad_route->ip[3],
                                 ad_route->route_masklen);
            }
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "AD-idx:[0x%x]\n", ad_route->ad_idx);
        }
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------route num:[%u]----------\n", p_tcam_item->trie->trie->count);
        ret = sys_nalpm_trie_traverse(p_tcam_item->trie->trie, _sys_tsingma_nalpm_dump_route_trie_node, &dump_node, _TRIE_DUMP_TRAVERSE);
    }

    if (p_dump->mode != 3)
    {
       return -1;
    }

    return ret;
}

/*
mode:
0 -->tcam
1 -> sram
2 -> by_route
3 -> tree
*/
int32
sys_tsingma_nalpm_dump_route_trie(uint8 lchip,
                                  uint16 index,
                                  ctc_ipuc_param_t* p_ipuc_param,
                                  uint8 mode,
                                  uint8 detail,
                                  uint16 vrf_max)
{
    int32 ret = CTC_E_NONE;
    uint16 vrfid = 0;
    uint8 ip_ver = 0;
    sys_nalpm_route_info_t*  p_route_info = NULL;
    sys_nalpm_dump_route_info_t dump;
    trie_dump_node_t dump_node;
    LCHIP_CHECK(lchip);

    SYS_NALPM_INIT_CHECK;

    ip_ver = p_ipuc_param->ip_ver;
    vrfid = p_ipuc_param->vrf_id;
    vrf_max = vrf_max == 0?p_ipuc_param->vrf_id:vrf_max;


    CTC_MAX_VALUE_CHECK(vrfid, MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));
    CTC_MAX_VALUE_CHECK(vrf_max, MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));
    CTC_MAX_VALUE_CHECK(ip_ver, CTC_IP_VER_6);
    sal_memset(&dump, 0, sizeof(dump));
    dump_node.user_data = &dump;
    dump.index = index;
    dump.mode = mode;
    dump.detail = detail;
    dump_node.lchip = lchip;

    SYS_IPUC_LOCK;

    if (dump.mode == 2)
    {
        /* prepare data */
        ip_ver = p_ipuc_param->ip_ver;

        p_route_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
        if (NULL == p_route_info)
        {
            SYS_IPUC_UNLOCK;
            return CTC_E_NO_MEMORY;
        }

        sal_memset(p_route_info, 0 , (ROUTE_INFO_SIZE(ip_ver)));
        p_route_info->ip_ver = ip_ver;
        sal_memcpy(p_route_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
        p_route_info->route_masklen = p_ipuc_param->masklen;
        p_route_info->vrf_id = p_ipuc_param->vrf_id;

        dump.p_route_info = p_route_info;
    }

    for (vrfid = p_ipuc_param->vrf_id; vrfid <= vrf_max; vrfid++)
    {
        if (NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]
            || NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie)
        {
            continue;
        }

        ret = sys_nalpm_trie_traverse(g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrfid]->trie,
                                      _sys_tsingma_nalpm_dump_route_trie, &dump_node, _TRIE_DUMP_TRAVERSE);
    }

    if (dump.mode == 2)
    {
        mem_free(p_route_info);
    }

    SYS_IPUC_UNLOCK;
    return ret;
}

int32
sys_tsingma_nalpm_show_route_info(uint8 lchip, void* p_ipuc_param_v)
{
    sys_nalpm_route_info_t*  p_route_info = NULL;
    sys_nalpm_route_store_info_t lkp_rlt;
    sys_nalpm_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm_tcam_item_t* p_tcam_item = NULL;
    sys_ipuc_tcam_data_t tcam_data;
    uint8 ip_ver = 0;
    int32 ret = CTC_E_NONE;
    uint32 pfx[4] = {0};
    uint32 hw_sram_idx = 0;
    uint32 table_id[2] = {0};
    ctc_ipuc_param_t* p_ipuc_param = (ctc_ipuc_param_t*)p_ipuc_param_v;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_NALPM_INIT_CHECK;

    /* prepare data */
    ip_ver = p_ipuc_param->ip_ver;

    p_route_info = mem_malloc(MEM_IPUC_MODULE, ROUTE_INFO_SIZE(ip_ver));
    if(NULL == p_route_info)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_route_info, 0 , (ROUTE_INFO_SIZE(ip_ver)));
    p_route_info->ip_ver = ip_ver;
    sal_memcpy(p_route_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_route_info->route_masklen = p_ipuc_param->masklen;
    p_route_info->vrf_id = p_ipuc_param->vrf_id;
    SYS_IP_V6_SORT(p_route_info);

    /* 1. lookup sw node */
    ret = _sys_tsingma_nalpm_route_lkp( lchip, p_route_info,p_lkp_rlt);
    mem_free(p_route_info);
    if(ret < 0 || !p_lkp_rlt->tcam_hit || (!p_lkp_rlt->sram_hit && p_ipuc_param->masklen != 0))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "(%d)   can't find  router\n",__LINE__);
        return CTC_E_NOT_EXIST;
    }

    if (MCHIP_IPUC(lchip)->show_tcam_key)
    {
        tcam_data.key_type = SYS_IPUC_TCAM_FLAG_ALPM;
        tcam_data.key_index = p_lkp_rlt->p_tcam_item->tcam_idx;
        tcam_data.masklen = p_ipuc_param->masklen;
        tcam_data.ipuc_param = p_ipuc_param;
        MCHIP_IPUC(lchip)->show_tcam_key(lchip, &tcam_data);
    }
    if(p_ipuc_param->masklen == 0)
    {
        return ret;
    }
    p_tcam_item = p_lkp_rlt->p_tcam_item;
    hw_sram_idx = sys_tsingma_nalpm_get_hw_sram_idx(lchip, p_tcam_item, p_lkp_rlt->snake_idx);

    if(DRV_IS_TSINGMA(lchip))
    {
        if(p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V4_32)
        {
            if(p_lkp_rlt->snake_idx < g_sys_nalpm_master[lchip]->snake_per_group)
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "DsNeoLpmIpv4Bit32Snake", hw_sram_idx);
            }
            else
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "DsNeoLpmIpv4Bit32Snake1", hw_sram_idx);
            }
        }
        if(p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_64)
        {
            if(p_lkp_rlt->snake_idx < g_sys_nalpm_master[lchip]->snake_per_group)
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "DsNeoLpmIpv6Bit64Snake", hw_sram_idx);
            }
            else
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "DsNeoLpmIpv6Bit64Snake1", hw_sram_idx);
            }
        }
        if(p_tcam_item->sram_type == SYS_NALPM_SRAM_TYPE_V6_128)
        {
            if(p_lkp_rlt->snake_idx < g_sys_nalpm_master[lchip]->snake_per_group)
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "DsNeoLpmIpv6Bit128Snake", hw_sram_idx);
            }
            else
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "DsNeoLpmIpv6Bit128Snake1", hw_sram_idx);
            }
        }
    }
    else
    {
        sys_nalpm_get_table_id(lchip, p_tcam_item->sram_type, p_lkp_rlt->snake_idx, &table_id[0], &table_id[1]);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", DRV_TABLE_NAME(lchip, table_id[0]), hw_sram_idx);
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "Sram index", p_tcam_item->sram_idx);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "snake index", p_lkp_rlt->snake_idx);
    //SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "snake index", p_lkp_rlt->snake_idx%g_sys_nalpm_master[lchip]->snake_per_group);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "entry_offset", p_lkp_rlt->entry_offset);
    SYS_NALPM_CONVERT_TO_MSB(p_tcam_item->p_prefix_info->ip, p_tcam_item->p_prefix_info->tcam_masklen, pfx, ip_ver);
    if (CTC_IP_VER_4 == ip_ver)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:[0x%08x/%d]\n","tcam prefix",pfx[0],p_tcam_item->p_prefix_info->tcam_masklen);
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:[0x%08x:%08x:%08x:%08x/%d]\n",
                        "tcam prefix",
                        pfx[0],
                        pfx[1],
                        pfx[2],
                        pfx[3],
                        p_tcam_item->p_prefix_info->tcam_masklen);
    }

    return ret;
}

int32
sys_tsingma_nalpm_show_sram_usage(uint8 lchip)
{
    sys_usw_opf_t opf;
    uint32 entry_num = 0;
    opf.pool_index = 0;
    SYS_NALPM_INIT_CHECK;
    opf.pool_type = g_sys_nalpm_master[lchip]->opf_type_nalpm;
    sys_usw_ftm_query_table_entry_num(lchip, DsNeoLpmIpv4Bit32Snake_t, &entry_num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Lchip %d SRAM usage: %u/%u 3W\n", lchip, sys_usw_opf_get_alloced_cnt(lchip, &opf)*g_sys_nalpm_master[lchip]->snake_per_group, entry_num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------------------------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Auto run fragment merge: %u\n", g_sys_nalpm_master[lchip]->frag_arrange_enable);
    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_dump_db(uint8 lchip, sal_file_t p_f, ctc_global_dump_db_t* p_dump_param)
{
    uint32 i = 0;
    SYS_NALPM_INIT_CHECK;
    SYS_DUMP_DB_LOG(p_f, "%s\n", "# NALPM");
    SYS_DUMP_DB_LOG(p_f, "%s\n", "Master config:");
    SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
    SYS_DUMP_DB_LOG(p_f, "%-30s: %u\n", "Split mode", g_sys_nalpm_master[lchip]->split_mode);
    SYS_DUMP_DB_LOG(p_f, "%-30s: %u\n", "Nalpm opf type", g_sys_nalpm_master[lchip]->opf_type_nalpm);
    SYS_DUMP_DB_LOG(p_f, "%-30s: %u\n", "Ipsa enable", g_sys_nalpm_master[lchip]->ipsa_enable);
    SYS_DUMP_DB_LOG(p_f, "%-30s: %u\n", "Auto frag arrange enable", g_sys_nalpm_master[lchip]->frag_arrange_enable);
    SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
    if (p_dump_param->detail)
    {
        SYS_DUMP_DB_LOG(p_f, "%s\n", "IPv4 route cnt per vrf:");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%-10s%-10s\n", "vrfid", "count");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        for(i = 0; i <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); i++)
        {
            if (0 == g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_4][i])
            {
                continue;
            }
            SYS_DUMP_DB_LOG(p_f, "%-10u%-10u\n", i, g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_4][i]);
        }
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "IPv6 route cnt per vrf:");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%-10s%-10s\n", "vrfid", "count");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        for(i = 0; i <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); i++)
        {
            if (0 == g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_6][i])
            {
                continue;
            }
            SYS_DUMP_DB_LOG(p_f, "%-10u%-10u\n", i, g_sys_nalpm_master[lchip]->vrf_route_cnt[CTC_IP_VER_6][i]);
        }
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
    }
    sys_usw_opf_fprint_alloc_used_info(lchip, g_sys_nalpm_master[lchip]->opf_type_nalpm, p_f);

    return CTC_E_NONE;

}

STATIC int16
_sys_tsingma_nalpm_get_min_bucket_ent(uint8 ip_ver,uint8 is_sub_bucket,int16 max_bucket_ent)
{
    /*  [i][][] for ipv4/64v6/128v6
        [][j][] for 1-5 sram and ipsa_enable 
        [][][k] for bucket and sub bucket*/
    int16  min_bucket[MAX_CTC_IP_VER + 1][10][2] = 
                    {
                        {/*   6    12    18     24    30       36      42     48      54       60*/
                            {3,2},{5,4},{7,6},{9,8},{11,10},{13,12},{15,14},{17,16},{19,18},{21,20}
                        },
                        {/*   2     4     6     8     10    12    14    16    18    20*/
                            {1,1},{2,2},{3,3},{3,3},{4,4},{5,5},{5,5},{6,6},{7,7},{7,7}
                        },
                        {/*   3     6     9     12    15    18    21    24     27     30*/
                            {2,1},{3,3},{4,4},{5,5},{6,6},{7,7},{8,8},{9,9},{10,10},{11,11}
                        }
                    };
    int8 i = ip_ver;
    int8 j = 0;
    int8 k = 0;

    if (i == CTC_IP_VER_4)
    {
        j = max_bucket_ent/ROUTE_NUM_PER_SNAKE_V4;
    }
    else if (i == CTC_IP_VER_6)
    {
        j = max_bucket_ent/ROUTE_NUM_PER_SNAKE_V6_128;
    }
    else if (i == MAX_CTC_IP_VER)
    {
        j = max_bucket_ent/ROUTE_NUM_PER_SNAKE_V6_64;
    }
    else
    {
        return 0;
    }

    j--;
    if(j > 9 || j <= 0)
    {
        return 0;
    }

    k = is_sub_bucket ? 1 : 0;


    return min_bucket[i][j][k];
}

STATIC int32
_sys_tsingma_nalpm_show_calculate_cnt(uint8 lchip)
{
    sys_usw_opf_t opf;
    int32 ipv4_max_cnt = 0;
    int32 ipv4_min_cnt = 0;
    int32 ipv6_max_cnt = 0;
    int32 ipv6_min_cnt = 0;
    int32 max_tcam = 0;
    uint16 v4_max_bkt_ent = 0;
    uint16 v6_max_bkt_ent = 0;
    uint16 v4_min_bkt_ent = 0;
    uint16 v6_min_bkt_ent = 0;
    uint16 tcam_left = 0;
    uint16 bucket_left = 0;
    uint16 real_bucket_left = bucket_left;
    uint8 ip_ver = 0 ;


    v4_max_bkt_ent = NALPM_BUKCET_SNAKE_NUM(lchip) * ROUTE_NUM_PER_SNAKE_V4;
    v6_max_bkt_ent = g_sys_nalpm_master[lchip]->use_snake64 ? NALPM_BUKCET_SNAKE_NUM(lchip) * ROUTE_NUM_PER_SNAKE_V6_64 :
                                                              NALPM_BUKCET_SNAKE_NUM(lchip) * ROUTE_NUM_PER_SNAKE_V6_128; 
    max_tcam = (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM] +
                p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM]);

    opf.pool_index = 0;
    opf.multiple = 0;
    opf.reverse = 0;
    opf.pool_type = g_sys_nalpm_master[lchip]->opf_type_nalpm;
    bucket_left = g_sys_nalpm_master[lchip]->bkt_depth - sys_usw_opf_get_alloced_cnt(lchip, &opf);


    /* calculate IPV4 */
    ip_ver = CTC_IP_VER_4;
    tcam_left = max_tcam -
                (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_TCAM]+ 
                 p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM]*4);
    real_bucket_left = DRV_IS_TSINGMA(lchip) ? bucket_left/4 : bucket_left;
    v4_min_bkt_ent = _sys_tsingma_nalpm_get_min_bucket_ent(ip_ver,0,v4_max_bkt_ent);
    if(tcam_left > real_bucket_left)
    {
        ipv4_max_cnt = real_bucket_left * v4_max_bkt_ent;
        ipv4_min_cnt = real_bucket_left * v4_min_bkt_ent;
/*      if(DRV_IS_TMM(lchip))
        {
            v4_min_bkt_ent = _sys_tsingma_nalpm_get_min_bucket_ent(ip_ver,1,v4_max_bkt_ent);
            ipv4_min_cnt += (tcam_left - bucket_left-1) * v4_min_bkt_ent;  minus 1 for root node got no subbukcet
            can't calculate subbucket correctly ,code for reference.
        } */
    }
    else
    {
        ipv4_max_cnt = tcam_left * v4_max_bkt_ent;
        ipv4_min_cnt = tcam_left * v4_min_bkt_ent;
    }
    ipv4_max_cnt += (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_TCAM]-
                     (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_LPM] -
                      p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_ALPM]) -
                     p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_CONFLICT_TCAM])*v4_max_bkt_ent -
                    p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_ALPM];

    /* calculate IPV6 */
    ip_ver = g_sys_nalpm_master[lchip]->use_snake64 ? MAX_CTC_IP_VER : CTC_IP_VER_6;
    tcam_left /= 4;
    real_bucket_left = DRV_IS_TSINGMA(lchip) ? bucket_left/8 : bucket_left;
    v6_min_bkt_ent = _sys_tsingma_nalpm_get_min_bucket_ent(ip_ver,0,v6_max_bkt_ent);
    if(tcam_left > real_bucket_left)
    {
        ipv6_max_cnt = real_bucket_left * v6_max_bkt_ent;
        ipv6_min_cnt = real_bucket_left * v6_min_bkt_ent;
    }
    else
    {
        ipv6_max_cnt = tcam_left * v6_max_bkt_ent;
        ipv6_min_cnt = tcam_left * v6_min_bkt_ent;
    }
    ipv6_max_cnt += (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM]-
                     (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_LPM] -
                      p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_ALPM]) -
                     p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_CONFLICT_TCAM])*v6_max_bkt_ent -
                    p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_ALPM];

    if(!p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM])
    {
        ipv6_max_cnt = 0;
        ipv6_min_cnt = 0;
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s\n", "-----------------------------------------------------------------------------------");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s\n", "LPM Route resource left");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %8d -- %8d\n", "All resource for IPv4", ipv4_min_cnt , ipv4_max_cnt);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %8d -- %8d\n", "All resource for IPv6", ipv6_min_cnt , ipv6_max_cnt);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s\n", "-----------------------------------------------------------------------------------");
    return CTC_E_NONE;
}

int32
sys_tsingma_nalpm_show_status(uint8 lchip)
{
    uint16 v4_bkt_ent = 0;
    uint16 v6_64_bkt_ent = 0;
    uint16 v6_128_bkt_ent = 0;

    SYS_NALPM_INIT_CHECK;

#define MIN(a, b) (a<b?a:b)

    v4_bkt_ent = NALPM_BUKCET_SNAKE_NUM(lchip) *ROUTE_NUM_PER_SNAKE_V4;
    v6_64_bkt_ent = NALPM_BUKCET_SNAKE_NUM(lchip) *ROUTE_NUM_PER_SNAKE_V6_64;
    v6_128_bkt_ent = NALPM_BUKCET_SNAKE_NUM(lchip) *ROUTE_NUM_PER_SNAKE_V6_128;



    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "MergerCnt", g_sys_nalpm_master[lchip]->merge_cnt);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "ipv6 use snake64", g_sys_nalpm_master[lchip]->use_snake64);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "ipv6_couple  Mode", g_sys_nalpm_master[lchip]->ipv6_couple_mode);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Split Mode", g_sys_nalpm_master[lchip]->split_mode);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Ipsa Enable", g_sys_nalpm_master[lchip]->ipsa_enable);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Bucket Depth", DRV_IS_TSINGMA(lchip) ? g_sys_nalpm_master[lchip]->bkt_depth/4 : g_sys_nalpm_master[lchip]->bkt_depth);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Real Bucket Depth", DRV_IS_TSINGMA(lchip) ? g_sys_nalpm_master[lchip]->real_bkt_depth/4 : g_sys_nalpm_master[lchip]->real_bkt_depth);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Snake Per Group", g_sys_nalpm_master[lchip]->snake_per_group);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Snake Group num", g_sys_nalpm_master[lchip]->snake_group_num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Ipv4 Entry/Bucket", v4_bkt_ent);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Ipv6(64) Entry/Bucket",v6_64_bkt_ent);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-25s: %15d\n", "Ipv6(128) Entry/Bucket", v6_128_bkt_ent);
    sys_tsingma_nalpm_show_sram_usage(lchip);
    if(!p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT])
    {
        _sys_tsingma_nalpm_show_calculate_cnt(lchip);
    }

    return CTC_E_NONE;
}



int32
sys_tsingma_nalpm_check_route(uint8 lchip, void *p_info, void* cb)
{
#ifdef IPUC_TEST_STUB
    uint32 * p_trie_key = NULL;
    uint8 ip_ver = 0;
    uint16 vrf_id = 0;
    trie_chk_info_t *info = (trie_chk_info_t *) p_info;

    SYS_NALPM_INIT_CHECK;

    ip_ver = info->ip_ver;
    vrf_id = info->vrf_id;

    if(NULL == g_sys_nalpm_master[lchip]->prefix_trie[ip_ver][vrf_id])
    {
        return CTC_E_NOT_EXIST;
    }

    p_trie_key = mem_malloc(MEM_IPUC_MODULE, IP_ADDR_SIZE(ip_ver));
    if(!p_trie_key)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_trie_key, 0 ,(IP_ADDR_SIZE(ip_ver)));
    sal_memcpy(p_trie_key, info->ip, (IP_ADDR_SIZE(ip_ver)));



   info->cb = _sys_tsingma_nalpm_dump_route_trie_node;



    CTC_ERROR_RETURN(sys_trie_check_node(g_sys_nalpm_master[lchip]->route_db_trie[ip_ver][vrf_id], p_trie_key,
                                            info->mask_len, (trie_check_cb_f)cb, (trie_chk_info_t *)info));

    mem_free(p_trie_key);

#endif

    return 0;
}
#ifdef IPUC_TEST_STUB
int32
sys_tingma_nalpm_dump_db_route_trie(uint8 lchip, uint8 ip_ver, uint16 vrf_id)
{

    trie_node_t *trie = NULL;
    trie_dump_node_t dump_node;

    SYS_NALPM_INIT_CHECK;

    trie = g_sys_nalpm_master[lchip]->route_db_trie[ip_ver][vrf_id]->trie;

    dump_node.father = trie;
    dump_node.father_lvl = 0;
    dump_node.root =  trie;


    sys_nalpm_trie_traverse(trie, _sys_tsingma_nalpm_dump_route_trie_node, &dump_node, _TRIE_DUMP_TRAVERSE);


    return 0;
}
#endif

int32
sys_tsingma_nalpm_move_hit_en(uint8 lchip, uint8 enable)
{
    LCHIP_CHECK(lchip);
    SYS_NALPM_INIT_CHECK;
    SYS_IPUC_LOCK;
    g_sys_nalpm_master[lchip]->move_hit_en = enable ? 1 : 0;
    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}
#endif

